@osfactory/har 0.52.0 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -69193,7 +69193,7 @@ function harnessExists(repoPath) {
69193
69193
  // src/harness/plugins.ts
69194
69194
  init_schema2();
69195
69195
  init_stages();
69196
- var PLUGIN_IDS = ["playwright", "rocketsim", "kerno", "gitleaks"];
69196
+ var PLUGIN_IDS = ["playwright", "rocketsim", "kerno", "gitleaks", "trivy"];
69197
69197
  var PluginManifestFileSchema = external_exports.object({
69198
69198
  src: external_exports.string().min(1),
69199
69199
  dest: external_exports.string().min(1),
@@ -1,7 +1,7 @@
1
1
  # HAR Stages — authoring guide
2
2
 
3
3
  Stages are the harness's single vocabulary for runnable checks and lifecycle
4
- actions. Everything — shipped plugins (`playwright`, `rocketsim`, `kerno`, `gitleaks`), your
4
+ actions. Everything — shipped plugins (`playwright`, `rocketsim`, `kerno`, `gitleaks`, `trivy`), your
5
5
  project's test/lint commands, bespoke validation scripts — registers in
6
6
  `.har/stages.json` with the same schema, and agents interact with stages only
7
7
  through that registry (CLI `har env verify`, MCP `har_run_stage` /
@@ -91,6 +91,8 @@ committed.
91
91
 
92
92
  `har env add-plugin --list` shows available plugins; `har env add-plugin
93
93
  playwright` (web), `har env add-plugin rocketsim` (iOS), or `har env
94
- add-plugin kerno` (backend) or `har env add-plugin gitleaks` (secrets scanning, any stack) installs one. A
94
+ add-plugin kerno` (backend), `har env add-plugin gitleaks` (secrets scanning, any
95
+ stack), or `har env add-plugin trivy` (dependency + IaC security scan, any stack)
96
+ installs one. A
95
97
  plugin is just packaging: it copies files, merges `package.json` fragments,
96
98
  and registers stages through the exact same registry as `add-stage --custom`.
@@ -1,7 +1,7 @@
1
1
  # HAR Stages — authoring guide
2
2
 
3
3
  Stages are the harness's single vocabulary for runnable checks and lifecycle
4
- actions. Everything — shipped plugins (`playwright`, `rocketsim`, `kerno`, `gitleaks`), your
4
+ actions. Everything — shipped plugins (`playwright`, `rocketsim`, `kerno`, `gitleaks`, `trivy`), your
5
5
  project's test/lint commands, bespoke validation scripts — registers in
6
6
  `.har/stages.json` with the same schema, and agents interact with stages only
7
7
  through that registry (CLI `har env verify`, MCP `har_run_stage` /
@@ -91,6 +91,8 @@ committed.
91
91
 
92
92
  `har env add-plugin --list` shows available plugins; `har env add-plugin
93
93
  playwright` (web), `har env add-plugin rocketsim` (iOS), or `har env
94
- add-plugin kerno` (backend) or `har env add-plugin gitleaks` (secrets scanning, any stack) installs one. A
94
+ add-plugin kerno` (backend), `har env add-plugin gitleaks` (secrets scanning, any
95
+ stack), or `har env add-plugin trivy` (dependency + IaC security scan, any stack)
96
+ installs one. A
95
97
  plugin is just packaging: it copies files, merges `package.json` fragments,
96
98
  and registers stages through the exact same registry as `add-stage --custom`.
@@ -1,7 +1,7 @@
1
1
  # HAR Stages — authoring guide
2
2
 
3
3
  Stages are the harness's single vocabulary for runnable checks and lifecycle
4
- actions. Everything — shipped plugins (`playwright`, `rocketsim`, `kerno`, `gitleaks`), your
4
+ actions. Everything — shipped plugins (`playwright`, `rocketsim`, `kerno`, `gitleaks`, `trivy`), your
5
5
  project's test/lint commands, bespoke validation scripts — registers in
6
6
  `.har/stages.json` with the same schema, and agents interact with stages only
7
7
  through that registry (CLI `har env verify`, MCP `har_run_stage` /
@@ -91,6 +91,8 @@ committed.
91
91
 
92
92
  `har env add-plugin --list` shows available plugins; `har env add-plugin
93
93
  playwright` (web), `har env add-plugin rocketsim` (iOS), or `har env
94
- add-plugin kerno` (backend) or `har env add-plugin gitleaks` (secrets scanning, any stack) installs one. A
94
+ add-plugin kerno` (backend), `har env add-plugin gitleaks` (secrets scanning, any
95
+ stack), or `har env add-plugin trivy` (dependency + IaC security scan, any stack)
96
+ installs one. A
95
97
  plugin is just packaging: it copies files, merges `package.json` fragments,
96
98
  and registers stages through the exact same registry as `add-stage --custom`.
@@ -0,0 +1,40 @@
1
+ name: Trivy scan
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ scan:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ contents: read
13
+ security-events: write
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - name: Run Trivy (filesystem scan)
17
+ uses: aquasecurity/trivy-action@a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 # v0.36.0
18
+ with:
19
+ scan-type: fs
20
+ scan-ref: .
21
+ scanners: vuln,misconfig
22
+ severity: HIGH,CRITICAL
23
+ format: sarif
24
+ output: trivy-results.sarif
25
+ exit-code: 0
26
+ - name: Upload SARIF to GitHub code scanning
27
+ if: always()
28
+ uses: github/codeql-action/upload-sarif@v3
29
+ with:
30
+ sarif_file: trivy-results.sarif
31
+ - name: Fail on HIGH/CRITICAL findings
32
+ uses: aquasecurity/trivy-action@a9c7b0f06e461e9d4b4d1711f154ee024b8d7ab8 # v0.36.0
33
+ with:
34
+ scan-type: fs
35
+ scan-ref: .
36
+ scanners: vuln,misconfig
37
+ severity: HIGH,CRITICAL
38
+ format: table
39
+ exit-code: 1
40
+ skip-setup-trivy: true
@@ -0,0 +1,88 @@
1
+ # Trivy Vulnerability & Misconfiguration Scanning
2
+
3
+ The `vuln-scan` stage runs [Trivy](https://trivy.dev) against the agent's
4
+ worktree: known CVEs in dependency lockfiles (`vuln` scanner) and IaC/config
5
+ misconfigurations in Terraform, Dockerfiles, Kubernetes manifests, Helm charts,
6
+ and CloudFormation (`misconfig` scanner). Full verify (`verify --full`) runs it
7
+ automatically.
8
+
9
+ Trivy absorbed **tfsec** — its Terraform checks now live in Trivy's `misconfig`
10
+ scanner, so this plugin covers the Terraform/IaC use case without a separate tool.
11
+
12
+ ## What runs
13
+
14
+ ```bash
15
+ trivy fs --scanners vuln,misconfig --severity HIGH,CRITICAL --exit-code 1 \
16
+ --format json --output .har/artifacts/vuln-scan/report.json <work-dir>
17
+ ```
18
+
19
+ The stage **fails** when any finding at or above the severity threshold exists.
20
+ Findings below the threshold are not reported at all — raise or lower the bar
21
+ via configuration.
22
+
23
+ ## Configuration
24
+
25
+ Set in `harness.env` (or export before running):
26
+
27
+ | Variable | Default | Purpose |
28
+ |----------|---------|---------|
29
+ | `HARNESS_TRIVY_SEVERITY` | `HIGH,CRITICAL` | Comma-separated severities that fail the stage (`UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL`) |
30
+ | `HARNESS_TRIVY_SCANNERS` | `vuln,misconfig` | Scanners to run (`vuln`, `misconfig`, `secret`, `license`) |
31
+ | `TRIVY_CACHE_DIR` | `~/.cache/trivy` | Vulnerability DB cache — kept **outside** the worktrees so every slot shares one DB download (~60MB, refreshed every ~6h) |
32
+
33
+ ## Artifacts
34
+
35
+ | Path | Contents |
36
+ |------|----------|
37
+ | `.har/artifacts/vuln-scan/report.json` | Full Trivy JSON report (machine-readable) |
38
+ | `.har/artifacts/vuln-scan/summary.txt` | Human-readable table (`trivy convert`) |
39
+
40
+ Artifacts always land in the **main repo root** `.har/artifacts/`, not the worktree.
41
+
42
+ ## Suppressing findings
43
+
44
+ Add IDs to `.trivyignore` at the repo root — one CVE / check ID per line, no
45
+ trailing comments on the ID line:
46
+
47
+ ```
48
+ # Accepted risk: dev-only dependency, fix tracked in TICKET-123 (expires when bumped)
49
+ CVE-2021-23337
50
+ # Terraform check that conflicts with our architecture
51
+ AVD-AWS-0086
52
+ ```
53
+
54
+ The stage passes the **worktree's** copy via `--ignorefile`, so a suppression
55
+ travels with the change batch that introduces it and gets reviewed in the same
56
+ PR. Prefer fixing (bump the dependency, correct the config) over ignoring.
57
+
58
+ ## Adaptations per repo
59
+
60
+ - **Container images**: the default stage scans the filesystem only. If the repo
61
+ builds an image, add a second invocation after the build:
62
+ `trivy image --severity "$SEVERITY" --exit-code 1 <image:tag>`.
63
+ - **Monorepos**: scope the scan by replacing `"$WORK_DIR"` with a subdirectory,
64
+ or add `--skip-dirs 'vendor/**,examples/**'`.
65
+ - **Lockfile-only scanning**: Trivy reads lockfiles (`package-lock.json`,
66
+ `yarn.lock`, `poetry.lock`, `go.sum`, `Cargo.lock`, …). Repos without a
67
+ lockfile get no dependency findings — commit one for meaningful results.
68
+ - **Secrets**: this harness pairs well with a dedicated secrets stage
69
+ (gitleaks plugin, which scans git history, not just the checkout). Add
70
+ `secret` to `HARNESS_TRIVY_SCANNERS` only if you don't run one.
71
+
72
+ ## CI and compliance platforms (Vanta, Drata, …)
73
+
74
+ The local stage is **pre-merge shift-left** — it keeps findings from ever
75
+ reaching your default branch. Compliance platforms never see local runs.
76
+
77
+ The optional workflow `.github/workflows/trivy.yml` runs the same scan in CI and
78
+ uploads SARIF to **GitHub code scanning** (the repo's Security tab). That
79
+ org-level layer is what compliance platforms like Vanta ingest as evidence (via
80
+ their GitHub integration). Keep both: local stage to catch early, CI workflow to
81
+ produce the evidence.
82
+
83
+ ## Running
84
+
85
+ ```bash
86
+ ./.har/stages/vuln-scan.sh 1 # standalone
87
+ ./.har/verify.sh 1 --full # as part of full verification
88
+ ```
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env bash
2
+ # Trivy vulnerability + misconfiguration scan for an agent slot.
3
+ # Scans the agent's worktree filesystem: dependency lockfiles (vuln) and
4
+ # IaC/config files — Terraform, Dockerfile, Kubernetes, CloudFormation (misconfig).
5
+ # Outputs JSON to stdout, human-readable progress to stderr.
6
+ #
7
+ # Usage: ./.har/stages/vuln-scan.sh <agent-id>
8
+ #
9
+ # Tune via harness.env or the environment:
10
+ # HARNESS_TRIVY_SEVERITY fail threshold (default: HIGH,CRITICAL)
11
+ # HARNESS_TRIVY_SCANNERS scanners to run (default: vuln,misconfig)
12
+ # TRIVY_CACHE_DIR vulnerability DB cache (default: ~/.cache/trivy —
13
+ # shared across slots so the DB downloads once)
14
+ #
15
+ # Prerequisite: ./.har/launch.sh <agent-id>
16
+ # See: ./.har/stages/TRIVY.md for the full adaptation guide.
17
+ set -euo pipefail
18
+
19
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20
+ HARNESS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
21
+ REPO_ROOT="$(cd "$HARNESS_DIR/.." && pwd)"
22
+ # agent-slot.sh expects SCRIPT_DIR to be .har/ (slot registry lives there)
23
+ SCRIPT_DIR="$HARNESS_DIR"
24
+
25
+ # shellcheck source=/dev/null
26
+ source "$HARNESS_DIR/harness.env"
27
+ # shellcheck source=/dev/null
28
+ source "$HARNESS_DIR/agent-slot.sh"
29
+
30
+ AGENT_ID="${1:?Usage: vuln-scan.sh <agent-id>}"
31
+
32
+ validate_agent_id "$AGENT_ID"
33
+
34
+ log() { echo "==> [vuln-scan agent-$AGENT_ID] $*" >&2; }
35
+
36
+ # ── Preflight ─────────────────────────────────────────────────────────────────
37
+ if ! command -v trivy >/dev/null 2>&1; then
38
+ echo "Error: trivy CLI not found." >&2
39
+ echo " Install: https://trivy.dev/latest/getting-started/installation/" >&2
40
+ echo " macOS: brew install trivy" >&2
41
+ echo " Linux: curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b ~/.local/bin" >&2
42
+ echo " Then re-run: ./.har/stages/vuln-scan.sh ${AGENT_ID}" >&2
43
+ exit 1
44
+ fi
45
+
46
+ # ── Resolve agent env ─────────────────────────────────────────────────────────
47
+ ENV_FILE="$(resolve_agent_env_file "$AGENT_ID" "$REPO_ROOT")" || {
48
+ echo "No .env.agent.${AGENT_ID} found." >&2
49
+ har_suggest_launch "$AGENT_ID" >&2
50
+ exit 1
51
+ }
52
+
53
+ set -a
54
+ # shellcheck source=/dev/null
55
+ source "$ENV_FILE"
56
+ set +a
57
+
58
+ WORK_DIR="$(resolve_agent_work_dir "$ENV_FILE")"
59
+
60
+ # ── Configuration ─────────────────────────────────────────────────────────────
61
+ SEVERITY="${HARNESS_TRIVY_SEVERITY:-HIGH,CRITICAL}"
62
+ SCANNERS="${HARNESS_TRIVY_SCANNERS:-vuln,misconfig}"
63
+ # One shared DB cache for every slot/worktree — first run downloads ~60MB,
64
+ # subsequent runs reuse it.
65
+ export TRIVY_CACHE_DIR="${TRIVY_CACHE_DIR:-$HOME/.cache/trivy}"
66
+
67
+ # ── Artifact directory ────────────────────────────────────────────────────────
68
+ ARTIFACT_DIR="$REPO_ROOT/.har/artifacts/vuln-scan"
69
+ mkdir -p "$ARTIFACT_DIR"
70
+ REPORT_JSON="$ARTIFACT_DIR/report.json"
71
+
72
+ # ── Scan ──────────────────────────────────────────────────────────────────────
73
+ # Use the WORKTREE's .trivyignore (not the main checkout's) so suppressions are
74
+ # reviewed with the code change that introduces them.
75
+ IGNOREFILE_ARGS=()
76
+ if [ -f "$WORK_DIR/.trivyignore" ]; then
77
+ IGNOREFILE_ARGS=(--ignorefile "$WORK_DIR/.trivyignore")
78
+ fi
79
+
80
+ log "Scanning $WORK_DIR (scanners: $SCANNERS, fail on: $SEVERITY)..."
81
+ START=$(now_ms)
82
+
83
+ set +e
84
+ trivy fs \
85
+ --scanners "$SCANNERS" \
86
+ --severity "$SEVERITY" \
87
+ --exit-code 1 \
88
+ --format json \
89
+ --output "$REPORT_JSON" \
90
+ --no-progress \
91
+ ${IGNOREFILE_ARGS[@]+"${IGNOREFILE_ARGS[@]}"} \
92
+ "$WORK_DIR" 2> >(sed 's/^/ /' >&2)
93
+ TRIVY_EXIT=$?
94
+ set -e
95
+
96
+ END=$(now_ms)
97
+ TOTAL_MS=$(( END - START ))
98
+
99
+ if [ ! -f "$REPORT_JSON" ]; then
100
+ echo "Error: trivy did not produce a report (exit $TRIVY_EXIT) — see stderr above." >&2
101
+ exit "$TRIVY_EXIT"
102
+ fi
103
+
104
+ # Human-readable summary next to the JSON report (best effort)
105
+ trivy convert --format table "$REPORT_JSON" > "$ARTIFACT_DIR/summary.txt" 2>/dev/null || true
106
+
107
+ # ── Output ────────────────────────────────────────────────────────────────────
108
+ STATUS="pass"
109
+ if [ "$TRIVY_EXIT" -ne 0 ]; then
110
+ STATUS="fail"
111
+ fi
112
+
113
+ node -e "
114
+ const fs = require('fs');
115
+ const report = JSON.parse(fs.readFileSync('$REPORT_JSON', 'utf8'));
116
+ const results = report.Results || [];
117
+ let vulnerabilities = 0;
118
+ let misconfigurations = 0;
119
+ let secrets = 0;
120
+ const findings = [];
121
+ for (const r of results) {
122
+ for (const v of r.Vulnerabilities || []) {
123
+ vulnerabilities++;
124
+ findings.push({ type: 'vuln', target: r.Target, id: v.VulnerabilityID, pkg: v.PkgName, installed: v.InstalledVersion, fixed: v.FixedVersion || null, severity: v.Severity, title: (v.Title || '').slice(0, 120) });
125
+ }
126
+ for (const m of r.Misconfigurations || []) {
127
+ misconfigurations++;
128
+ findings.push({ type: 'misconfig', target: r.Target, id: m.ID, severity: m.Severity, title: (m.Title || '').slice(0, 120) });
129
+ }
130
+ for (const s of r.Secrets || []) {
131
+ secrets++;
132
+ findings.push({ type: 'secret', target: r.Target, id: s.RuleID, severity: s.Severity, title: (s.Title || '').slice(0, 120) });
133
+ }
134
+ }
135
+ const out = {
136
+ status: '$STATUS',
137
+ stageId: 'vuln-scan',
138
+ kind: 'test',
139
+ agent_id: $AGENT_ID,
140
+ total_ms: $TOTAL_MS,
141
+ severity_threshold: '$SEVERITY',
142
+ scanners: '$SCANNERS',
143
+ counts: { vulnerabilities, misconfigurations, secrets },
144
+ findings: findings.slice(0, 50),
145
+ artifacts: [
146
+ { path: '.har/artifacts/vuln-scan/report.json', kind: 'report' },
147
+ { path: '.har/artifacts/vuln-scan/summary.txt', kind: 'report' }
148
+ ]
149
+ };
150
+ process.stdout.write(JSON.stringify(out, null, 2) + '\n');
151
+ "
152
+
153
+ if [ "$STATUS" = "fail" ]; then
154
+ log "✗ Findings at or above $SEVERITY — see .har/artifacts/vuln-scan/summary.txt"
155
+ exit 1
156
+ fi
157
+ log "✓ No findings at or above $SEVERITY (${TOTAL_MS}ms)"
@@ -0,0 +1,9 @@
1
+ # .trivyignore — suppress specific Trivy findings (one ID per line, no trailing
2
+ # comments). Prefer fixing over ignoring. Document every entry with a comment
3
+ # line above it saying why and when it can go.
4
+ #
5
+ # Example:
6
+ # # dev-only dependency, fix tracked in TICKET-123
7
+ # CVE-2021-23337
8
+ # # S3 public access is intentional for the www bucket
9
+ # AVD-AWS-0086
@@ -0,0 +1,32 @@
1
+ # Trivy plugin
2
+
3
+ Installs a `vuln-scan` stage that runs [Trivy](https://trivy.dev) against the
4
+ agent's worktree:
5
+
6
+ - **Dependency vulnerabilities** — known CVEs in lockfiles (`package-lock.json`,
7
+ `yarn.lock`, `poetry.lock`, `go.sum`, `Cargo.lock`, …)
8
+ - **IaC misconfigurations** — Terraform, Dockerfile, Kubernetes, Helm,
9
+ CloudFormation (Trivy absorbed tfsec, so this covers the Terraform use case)
10
+
11
+ ```bash
12
+ har env add-plugin trivy # --skip-ci to omit the GitHub workflow
13
+ ```
14
+
15
+ What it adds:
16
+
17
+ - `.har/stages/vuln-scan.sh` — the stage, registered in `.har/stages.json` and
18
+ appended to `verificationStages` (runs on `verify --full`)
19
+ - `.har/stages/TRIVY.md` — adaptation guide (severity threshold, scanners,
20
+ container-image scanning, monorepo scoping)
21
+ - `.trivyignore` — suppression file scaffold
22
+ - `.github/workflows/trivy.yml` *(optional)* — same scan in CI with SARIF upload
23
+ to GitHub code scanning; that org-level layer is what compliance platforms
24
+ like Vanta ingest as evidence
25
+
26
+ External requirement: the `trivy` binary (`brew install trivy` or the
27
+ [install script](https://trivy.dev/latest/getting-started/installation/)).
28
+ The stage fails fast with an install hint when it is missing.
29
+
30
+ Fail threshold defaults to `HIGH,CRITICAL` — override with
31
+ `HARNESS_TRIVY_SEVERITY` in `.har/harness.env`. Reports land in
32
+ `.har/artifacts/vuln-scan/`.
@@ -0,0 +1,44 @@
1
+ {
2
+ "id": "trivy",
3
+ "stageId": "vuln-scan",
4
+ "verificationStages": [
5
+ "typecheck",
6
+ "unit-tests",
7
+ "lint",
8
+ "vuln-scan"
9
+ ],
10
+ "stage": {
11
+ "id": "vuln-scan",
12
+ "kind": "test",
13
+ "description": "Trivy vulnerability + IaC misconfiguration scan (dependencies, Terraform, Dockerfile, K8s)",
14
+ "script": "stages/vuln-scan.sh",
15
+ "requiresAgentId": true,
16
+ "artifacts": [
17
+ {
18
+ "path": ".har/artifacts/vuln-scan",
19
+ "kind": "directory",
20
+ "description": "Trivy JSON report and human-readable summary"
21
+ },
22
+ {
23
+ "path": ".har/artifacts/vuln-scan/report.json",
24
+ "kind": "report"
25
+ }
26
+ ]
27
+ },
28
+ "files": [
29
+ { "src": ".har/stages/vuln-scan.sh", "dest": ".har/stages/vuln-scan.sh", "executable": true },
30
+ { "src": ".har/stages/TRIVY.md", "dest": ".har/stages/TRIVY.md" },
31
+ { "src": ".trivyignore", "dest": ".trivyignore" }
32
+ ],
33
+ "optionalFiles": [
34
+ { "src": ".github/workflows/trivy.yml", "dest": ".github/workflows/trivy.yml", "skipFlag": "skipCi" }
35
+ ],
36
+ "nextSteps": [
37
+ "Install trivy: brew install trivy (or https://trivy.dev/latest/getting-started/installation/)",
38
+ "./.har/launch.sh 1",
39
+ "./.har/stages/vuln-scan.sh 1",
40
+ "Open .har/artifacts/vuln-scan/summary.txt for findings",
41
+ "Tune HARNESS_TRIVY_SEVERITY / HARNESS_TRIVY_SCANNERS in .har/harness.env — read .har/stages/TRIVY.md"
42
+ ],
43
+ "docsPath": ".har/stages/TRIVY.md"
44
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osfactory/har",
3
- "version": "0.52.0",
3
+ "version": "0.53.0",
4
4
  "description": "Open harness for reproducible multi-agent coding workflows",
5
5
  "keywords": [
6
6
  "har",