Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9919afa0ee | ||
|
|
9ec07ff7a1 | ||
|
|
0e57c2d7a7 |
@@ -217,13 +217,16 @@ jobs:
|
|||||||
image: docker:27-cli
|
image: docker:27-cli
|
||||||
steps:
|
steps:
|
||||||
- name: Build, push and trigger orca redeploy
|
- name: Build, push and trigger orca redeploy
|
||||||
|
env:
|
||||||
|
TRAMITON_FETCH_TOKEN: ${{ secrets.TRAMITON_FETCH_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
apk add --no-cache git curl openssl
|
apk add --no-cache git curl openssl
|
||||||
git init && git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
git init && git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
||||||
git fetch --depth=1 origin "${GITHUB_SHA}" && git checkout FETCH_HEAD
|
git fetch --depth=1 origin "${GITHUB_SHA}" && git checkout FETCH_HEAD
|
||||||
IMAGE=registry.meghsakha.com/compliance-dashboard
|
IMAGE=registry.meghsakha.com/compliance-dashboard
|
||||||
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.meghsakha.com -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.meghsakha.com -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
||||||
docker build -f Dockerfile.dashboard -t "$IMAGE:latest" -t "$IMAGE:${GITHUB_SHA}" .
|
DOCKER_BUILDKIT=1 docker build --secret id=tramiton_token,env=TRAMITON_FETCH_TOKEN \
|
||||||
|
-f Dockerfile.dashboard -t "$IMAGE:latest" -t "$IMAGE:${GITHUB_SHA}" .
|
||||||
docker push "$IMAGE:latest" && docker push "$IMAGE:${GITHUB_SHA}"
|
docker push "$IMAGE:latest" && docker push "$IMAGE:${GITHUB_SHA}"
|
||||||
PAYLOAD=$(printf '{"ref":"refs/heads/main","repository":{"full_name":"sharang/compliance-scanner-agent"},"head_commit":{"id":"%s","message":"deploy dashboard"}}' "${GITHUB_SHA}")
|
PAYLOAD=$(printf '{"ref":"refs/heads/main","repository":{"full_name":"sharang/compliance-scanner-agent"},"head_commit":{"id":"%s","message":"deploy dashboard"}}' "${GITHUB_SHA}")
|
||||||
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "${{ secrets.ORCA_WEBHOOK_SECRET }}" | awk '{print $2}')
|
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "${{ secrets.ORCA_WEBHOOK_SECRET }}" | awk '{print $2}')
|
||||||
@@ -259,13 +262,16 @@ jobs:
|
|||||||
image: docker:27-cli
|
image: docker:27-cli
|
||||||
steps:
|
steps:
|
||||||
- name: Build, push and trigger orca redeploy
|
- name: Build, push and trigger orca redeploy
|
||||||
|
env:
|
||||||
|
TRAMITON_FETCH_TOKEN: ${{ secrets.TRAMITON_FETCH_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
apk add --no-cache git curl openssl
|
apk add --no-cache git curl openssl
|
||||||
git init && git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
git init && git remote add origin "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git"
|
||||||
git fetch --depth=1 origin "${GITHUB_SHA}" && git checkout FETCH_HEAD
|
git fetch --depth=1 origin "${GITHUB_SHA}" && git checkout FETCH_HEAD
|
||||||
IMAGE=registry.meghsakha.com/compliance-mcp
|
IMAGE=registry.meghsakha.com/compliance-mcp
|
||||||
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.meghsakha.com -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login registry.meghsakha.com -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
|
||||||
docker build -f Dockerfile.mcp -t "$IMAGE:latest" -t "$IMAGE:${GITHUB_SHA}" .
|
DOCKER_BUILDKIT=1 docker build --secret id=tramiton_token,env=TRAMITON_FETCH_TOKEN \
|
||||||
|
-f Dockerfile.mcp -t "$IMAGE:latest" -t "$IMAGE:${GITHUB_SHA}" .
|
||||||
docker push "$IMAGE:latest" && docker push "$IMAGE:${GITHUB_SHA}"
|
docker push "$IMAGE:latest" && docker push "$IMAGE:${GITHUB_SHA}"
|
||||||
PAYLOAD=$(printf '{"ref":"refs/heads/main","repository":{"full_name":"sharang/compliance-scanner-agent"},"head_commit":{"id":"%s","message":"deploy mcp"}}' "${GITHUB_SHA}")
|
PAYLOAD=$(printf '{"ref":"refs/heads/main","repository":{"full_name":"sharang/compliance-scanner-agent"},"head_commit":{"id":"%s","message":"deploy mcp"}}' "${GITHUB_SHA}")
|
||||||
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "${{ secrets.ORCA_WEBHOOK_SECRET }}" | awk '{print $2}')
|
SIG=$(printf '%s' "$PAYLOAD" | openssl dgst -sha256 -hmac "${{ secrets.ORCA_WEBHOOK_SECRET }}" | awk '{print $2}')
|
||||||
|
|||||||
+10
-1
@@ -7,7 +7,16 @@ ARG DOCS_URL=/docs
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
ENV DOCS_URL=${DOCS_URL}
|
ENV DOCS_URL=${DOCS_URL}
|
||||||
RUN dx build --release --package compliance-dashboard
|
# compliance-agent (a workspace member) depends on the private tramiton-core git
|
||||||
|
# repo, so the workspace resolve needs it even to build the dashboard.
|
||||||
|
# Authenticate the fetch with a PAT passed as a BuildKit secret.
|
||||||
|
RUN --mount=type=secret,id=tramiton_token \
|
||||||
|
if [ -s /run/secrets/tramiton_token ]; then \
|
||||||
|
git config --global \
|
||||||
|
url."https://sharang:$(cat /run/secrets/tramiton_token)@gitea.meghsakha.com/".insteadOf \
|
||||||
|
"ssh://git@gitea.meghsakha.com:22222/"; \
|
||||||
|
fi && \
|
||||||
|
CARGO_NET_GIT_FETCH_WITH_CLI=true dx build --release --package compliance-dashboard
|
||||||
|
|
||||||
FROM debian:bookworm-slim
|
FROM debian:bookworm-slim
|
||||||
RUN apt-get update && apt-get install -y ca-certificates libssl3 && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y ca-certificates libssl3 && rm -rf /var/lib/apt/lists/*
|
||||||
|
|||||||
+10
-1
@@ -2,7 +2,16 @@ FROM rust:1.94-bookworm AS builder
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN cargo build --release -p compliance-mcp
|
# compliance-agent (a workspace member) depends on the private tramiton-core git
|
||||||
|
# repo, so the workspace resolve needs it even to build the mcp binary.
|
||||||
|
# Authenticate the fetch with a PAT passed as a BuildKit secret.
|
||||||
|
RUN --mount=type=secret,id=tramiton_token \
|
||||||
|
if [ -s /run/secrets/tramiton_token ]; then \
|
||||||
|
git config --global \
|
||||||
|
url."https://sharang:$(cat /run/secrets/tramiton_token)@gitea.meghsakha.com/".insteadOf \
|
||||||
|
"ssh://git@gitea.meghsakha.com:22222/"; \
|
||||||
|
fi && \
|
||||||
|
CARGO_NET_GIT_FETCH_WITH_CLI=true cargo build --release -p compliance-mcp
|
||||||
|
|
||||||
FROM debian:bookworm-slim
|
FROM debian:bookworm-slim
|
||||||
RUN apt-get update && apt-get install -y ca-certificates libssl3 && rm -rf /var/lib/apt/lists/*
|
RUN apt-get update && apt-get install -y ca-certificates libssl3 && rm -rf /var/lib/apt/lists/*
|
||||||
|
|||||||
@@ -348,3 +348,43 @@ pub async fn detect_target(
|
|||||||
page: None,
|
page: None,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// POST /api/v1/targets/{id}/scan — trigger a scan for the target.
|
||||||
|
///
|
||||||
|
/// Dispatches to the unified pipeline when `UNIFIED_PIPELINE` is set (else the
|
||||||
|
/// legacy path). Runs in the background and returns immediately.
|
||||||
|
#[tracing::instrument(skip_all, fields(target_id = %id))]
|
||||||
|
pub async fn trigger_target_scan(
|
||||||
|
Extension(agent): AgentExt,
|
||||||
|
tenant: TenantCtx,
|
||||||
|
Path(id): Path<String>,
|
||||||
|
) -> Result<Json<serde_json::Value>, StatusCode> {
|
||||||
|
let oid = parse_oid(&id)?;
|
||||||
|
let db = tenant_db(&agent, &tenant).await?;
|
||||||
|
// 404 if the target doesn't exist for this tenant.
|
||||||
|
if db
|
||||||
|
.onboarded_targets()
|
||||||
|
.find_one(doc! { "_id": oid })
|
||||||
|
.await
|
||||||
|
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
return Err(StatusCode::NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
let agent_clone = (*agent).clone();
|
||||||
|
let tenant_id = tenant.0.tenant_id.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
if let Err(e) = agent_clone
|
||||||
|
.run_scan(
|
||||||
|
&tenant_id,
|
||||||
|
&id,
|
||||||
|
compliance_core::models::ScanTrigger::Manual,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
tracing::error!("Manual target scan failed for {id}: {e}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(Json(serde_json::json!({ "status": "scan_triggered" })))
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ pub fn build_router() -> Router {
|
|||||||
"/api/v1/targets/{id}/detect",
|
"/api/v1/targets/{id}/detect",
|
||||||
post(handlers::onboarding::detect_target),
|
post(handlers::onboarding::detect_target),
|
||||||
)
|
)
|
||||||
|
.route(
|
||||||
|
"/api/v1/targets/{id}/scan",
|
||||||
|
post(handlers::onboarding::trigger_target_scan),
|
||||||
|
)
|
||||||
.route("/api/v1/findings", get(handlers::list_findings))
|
.route("/api/v1/findings", get(handlers::list_findings))
|
||||||
.route("/api/v1/findings/{id}", get(handlers::get_finding))
|
.route("/api/v1/findings/{id}", get(handlers::get_finding))
|
||||||
.route(
|
.route(
|
||||||
|
|||||||
@@ -105,3 +105,19 @@ pub async fn fetch_applicable_scans(id: String) -> Result<ApplicableScansRespons
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| ServerFnError::new(e.to_string()))
|
.map_err(|e| ServerFnError::new(e.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trigger a scan for a target.
|
||||||
|
#[server]
|
||||||
|
pub async fn trigger_target_scan(id: String) -> Result<serde_json::Value, ServerFnError> {
|
||||||
|
let resp = super::agent_client::agent_request(
|
||||||
|
reqwest::Method::POST,
|
||||||
|
&format!("/api/v1/targets/{id}/scan"),
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.map_err(|e| ServerFnError::new(e.to_string()))?;
|
||||||
|
resp.json()
|
||||||
|
.await
|
||||||
|
.map_err(|e| ServerFnError::new(e.to_string()))
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use dioxus::prelude::*;
|
|||||||
|
|
||||||
use crate::components::page_header::PageHeader;
|
use crate::components::page_header::PageHeader;
|
||||||
use crate::infrastructure::onboarding::{
|
use crate::infrastructure::onboarding::{
|
||||||
create_target, detect_target, fetch_applicable_scans, ArtifactInputDto,
|
create_target, detect_target, fetch_applicable_scans, trigger_target_scan, ArtifactInputDto,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// (value, label, one-line description) for the 9 target families.
|
/// (value, label, one-line description) for the 9 target families.
|
||||||
@@ -113,6 +113,8 @@ pub fn OnboardingPage() -> Element {
|
|||||||
let mut error = use_signal(|| Option::<String>::None);
|
let mut error = use_signal(|| Option::<String>::None);
|
||||||
let mut scans = use_signal(Vec::<serde_json::Value>::new);
|
let mut scans = use_signal(Vec::<serde_json::Value>::new);
|
||||||
let mut suggested = use_signal(|| Option::<String>::None);
|
let mut suggested = use_signal(|| Option::<String>::None);
|
||||||
|
let mut created_id = use_signal(|| Option::<String>::None);
|
||||||
|
let mut scan_msg = use_signal(|| Option::<String>::None);
|
||||||
|
|
||||||
let step_now = step();
|
let step_now = step();
|
||||||
let can_advance_type = !name().trim().is_empty() && !target_type().trim().is_empty();
|
let can_advance_type = !name().trim().is_empty() && !target_type().trim().is_empty();
|
||||||
@@ -290,7 +292,27 @@ pub fn OnboardingPage() -> Element {
|
|||||||
ScanRow { scan: s }
|
ScanRow { scan: s }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div { style: "margin-top: 16px;",
|
if let Some(msg) = scan_msg() {
|
||||||
|
div { style: "margin-top: 8px; color: var(--success, #2a2);", "{msg}" }
|
||||||
|
}
|
||||||
|
div { style: "margin-top: 16px; display: flex; gap: 8px;",
|
||||||
|
button {
|
||||||
|
class: "btn btn-primary",
|
||||||
|
onclick: move |_| {
|
||||||
|
if let Some(id) = created_id() {
|
||||||
|
scan_msg.set(Some("Scan triggered...".to_string()));
|
||||||
|
spawn(async move {
|
||||||
|
match trigger_target_scan(id).await {
|
||||||
|
Ok(_) => scan_msg.set(Some(
|
||||||
|
"Scan started — findings will appear as it runs.".to_string(),
|
||||||
|
)),
|
||||||
|
Err(e) => scan_msg.set(Some(format!("Failed to start scan: {e}"))),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Run scan"
|
||||||
|
}
|
||||||
button {
|
button {
|
||||||
class: "btn btn-secondary",
|
class: "btn btn-secondary",
|
||||||
onclick: move |_| {
|
onclick: move |_| {
|
||||||
@@ -301,6 +323,8 @@ pub fn OnboardingPage() -> Element {
|
|||||||
artifacts.write().clear();
|
artifacts.write().clear();
|
||||||
scans.write().clear();
|
scans.write().clear();
|
||||||
suggested.set(None);
|
suggested.set(None);
|
||||||
|
created_id.set(None);
|
||||||
|
scan_msg.set(None);
|
||||||
error.set(None);
|
error.set(None);
|
||||||
},
|
},
|
||||||
"Onboard another"
|
"Onboard another"
|
||||||
@@ -348,6 +372,7 @@ pub fn OnboardingPage() -> Element {
|
|||||||
.and_then(|s| s.as_str())
|
.and_then(|s| s.as_str())
|
||||||
.map(String::from);
|
.map(String::from);
|
||||||
if let Some(id) = id {
|
if let Some(id) = id {
|
||||||
|
created_id.set(Some(id.clone()));
|
||||||
if let Ok(sc) = fetch_applicable_scans(id.clone()).await {
|
if let Ok(sc) = fetch_applicable_scans(id.clone()).await {
|
||||||
scans.set(sc.data.scans);
|
scans.set(sc.data.scans);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user