@osfactory/har 0.51.0 → 0.52.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"];
69196
+ var PLUGIN_IDS = ["playwright", "rocketsim", "kerno", "gitleaks"];
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`), your
4
+ actions. Everything — shipped plugins (`playwright`, `rocketsim`, `kerno`, `gitleaks`), 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,6 @@ 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) installs one. A
94
+ add-plugin kerno` (backend) or `har env add-plugin gitleaks` (secrets scanning, any stack) installs one. A
95
95
  plugin is just packaging: it copies files, merges `package.json` fragments,
96
96
  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`), your
4
+ actions. Everything — shipped plugins (`playwright`, `rocketsim`, `kerno`, `gitleaks`), 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,6 @@ 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) installs one. A
94
+ add-plugin kerno` (backend) or `har env add-plugin gitleaks` (secrets scanning, any stack) installs one. A
95
95
  plugin is just packaging: it copies files, merges `package.json` fragments,
96
96
  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`), your
4
+ actions. Everything — shipped plugins (`playwright`, `rocketsim`, `kerno`, `gitleaks`), 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,6 @@ 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) installs one. A
94
+ add-plugin kerno` (backend) or `har env add-plugin gitleaks` (secrets scanning, any stack) installs one. A
95
95
  plugin is just packaging: it copies files, merges `package.json` fragments,
96
96
  and registers stages through the exact same registry as `add-stage --custom`.
@@ -0,0 +1,29 @@
1
+ # Secrets scanning with the official Gitleaks action.
2
+ # Installed by `har env add-plugin gitleaks` (skip with --skip-ci).
3
+ #
4
+ # This CI run is what produces org-level scanning evidence that compliance
5
+ # platforms (Vanta, Drata, …) can ingest via your GitHub organization.
6
+ # Local .har stage runs are pre-merge protection only.
7
+ #
8
+ # GITLEAKS_LICENSE is required for organization repos (free — see
9
+ # https://github.com/gitleaks/gitleaks-action#environment-variables);
10
+ # personal accounts can omit it.
11
+ name: gitleaks
12
+
13
+ on:
14
+ push:
15
+ pull_request:
16
+ workflow_dispatch:
17
+
18
+ jobs:
19
+ scan:
20
+ name: gitleaks
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ with:
25
+ fetch-depth: 0
26
+ - uses: gitleaks/gitleaks-action@v2
27
+ env:
28
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29
+ GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}
@@ -0,0 +1,17 @@
1
+ # Gitleaks configuration — installed by `har env add-plugin gitleaks`.
2
+ # Extends the default ruleset; tune allowlists per repo.
3
+ # Docs: https://github.com/gitleaks/gitleaks#configuration
4
+
5
+ [extend]
6
+ useDefault = true
7
+
8
+ [allowlist]
9
+ description = "HAR harness defaults — dependencies, build outputs, harness artifacts"
10
+ paths = [
11
+ '''node_modules/''',
12
+ '''dist/''',
13
+ '''build/''',
14
+ '''vendor/''',
15
+ '''\.git/''',
16
+ '''\.har/artifacts/''',
17
+ ]
@@ -0,0 +1,77 @@
1
+ # Gitleaks secrets scan — authoring & adaptation guide
2
+
3
+ The `secrets-scan` stage runs [Gitleaks](https://github.com/gitleaks/gitleaks)
4
+ against the agent's work dir and fails when hardcoded secrets are found. It is a
5
+ **pre-merge, shift-left** check: it catches credentials before they ever reach the
6
+ default branch.
7
+
8
+ ## Prerequisite
9
+
10
+ The `gitleaks` binary must be on PATH:
11
+
12
+ ```bash
13
+ brew install gitleaks # macOS / Linuxbrew
14
+ # or download a release binary:
15
+ # https://github.com/gitleaks/gitleaks/releases
16
+ ```
17
+
18
+ The stage fails fast with an install hint when the binary is missing.
19
+
20
+ ## Running
21
+
22
+ ```bash
23
+ ./.har/stages/secrets-scan.sh <agent-id> # dir mode (default)
24
+ ./.har/stages/secrets-scan.sh <agent-id> git # history mode
25
+ ```
26
+
27
+ | Mode | What it scans | Use when |
28
+ |---|---|---|
29
+ | `dir` (default) | Every file currently in the work dir, **including uncommitted changes** | Normal verification — agents usually have uncommitted edits |
30
+ | `git` | The full git history of the worktree | Auditing that a secret never entered history (e.g. committed then removed) |
31
+
32
+ `git` mode on a repository with pre-existing leaks in old commits will fail on
33
+ findings unrelated to the current session. Generate a
34
+ [baseline](https://github.com/gitleaks/gitleaks#baseline) once and ignore known
35
+ history, or stick to `dir` mode for per-session verification.
36
+
37
+ ## Artifacts
38
+
39
+ Written to the **main repo root**, not the worktree:
40
+
41
+ | Path | Content |
42
+ |---|---|
43
+ | `.har/artifacts/secrets-scan/report.json` | JSON findings (rule, file, line — secret values are **redacted** via `--redact`) |
44
+ | `.har/artifacts/secrets-scan/gitleaks.log` | Full scanner output for debugging |
45
+
46
+ The stage prints a JSON summary to stdout: `status`, `leaks_found`, and the first
47
+ 20 findings. Exit code 0 = clean, 1 = leaks found, anything else = scanner error.
48
+
49
+ ## Tuning what gets flagged
50
+
51
+ The plugin ships a root `.gitleaks.toml` that extends the default ruleset and
52
+ allowlists dependency/build directories (`node_modules`, `dist`, `build`,
53
+ `vendor`, `.git`, `.har/artifacts`). Adapt it per repo:
54
+
55
+ - **False positive in a specific line** — append `# gitleaks:allow` to that line.
56
+ - **Test fixtures with dummy keys** — add the path to `[allowlist] paths` in
57
+ `.gitleaks.toml` (entries are regexes).
58
+ - **Custom internal token formats** — add `[[rules]]` entries; the shipped config
59
+ keeps `useDefault = true`, so default rules stay active.
60
+
61
+ Gitleaks automatically picks up `.gitleaks.toml` at the scan target root, so the
62
+ same config governs local stage runs and CI.
63
+
64
+ ## CI and compliance platforms (Vanta, Drata, …)
65
+
66
+ The optional workflow `.github/workflows/gitleaks.yml` (skipped with `--skip-ci`)
67
+ runs the official [`gitleaks/gitleaks-action`](https://github.com/gitleaks/gitleaks-action)
68
+ on pushes and pull requests.
69
+
70
+ Note the split: **this stage's local runs produce no compliance evidence** — they
71
+ exist so secrets never land on the default branch. Compliance platforms such as
72
+ Vanta ingest evidence from org-level sources (your GitHub organization, code
73
+ scanning results, etc.), which the CI workflow feeds. Keep both: the local stage
74
+ prevents findings; the CI run proves scanning happens.
75
+
76
+ Organizations (not personal accounts) need a free `GITLEAKS_LICENSE` secret for
77
+ the action — see the workflow comments.
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env bash
2
+ # Gitleaks secrets scan for an agent slot.
3
+ # Scans the agent work dir for hardcoded secrets and writes a redacted JSON report.
4
+ # Outputs JSON to stdout, human-readable progress to stderr.
5
+ #
6
+ # Usage: ./.har/stages/secrets-scan.sh <agent-id> [mode]
7
+ # mode (optional): dir (default) — scan the working tree, incl. uncommitted files
8
+ # git — scan the full git history of the worktree
9
+ #
10
+ # Prerequisite: gitleaks on PATH (brew install gitleaks, or a release binary
11
+ # from https://github.com/gitleaks/gitleaks/releases)
12
+ # See: ./.har/stages/GITLEAKS.md for the adaptation guide.
13
+ set -euo pipefail
14
+
15
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ HARNESS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
17
+ REPO_ROOT="$(cd "$HARNESS_DIR/.." && pwd)"
18
+ # agent-slot.sh expects SCRIPT_DIR to be .har/ (slot registry lives there)
19
+ SCRIPT_DIR="$HARNESS_DIR"
20
+
21
+ # shellcheck source=/dev/null
22
+ source "$HARNESS_DIR/harness.env"
23
+ # shellcheck source=/dev/null
24
+ source "$HARNESS_DIR/agent-slot.sh"
25
+
26
+ AGENT_ID="${1:?Usage: secrets-scan.sh <agent-id> [dir|git]}"
27
+ MODE="${2:-dir}"
28
+
29
+ validate_agent_id "$AGENT_ID"
30
+
31
+ if [ "$MODE" != "dir" ] && [ "$MODE" != "git" ]; then
32
+ echo "Error: unknown mode '$MODE' — expected 'dir' or 'git'." >&2
33
+ exit 1
34
+ fi
35
+
36
+ log() { echo "==> [secrets-scan agent-$AGENT_ID] $*" >&2; }
37
+
38
+ # ── Preflight ─────────────────────────────────────────────────────────────────
39
+ if ! command -v gitleaks >/dev/null 2>&1; then
40
+ echo "Error: gitleaks not found on PATH." >&2
41
+ echo " Install: brew install gitleaks" >&2
42
+ echo " Or download a release binary: https://github.com/gitleaks/gitleaks/releases" >&2
43
+ echo " Then re-run: ./.har/stages/secrets-scan.sh ${AGENT_ID}" >&2
44
+ exit 1
45
+ fi
46
+
47
+ # ── Artifact directory ────────────────────────────────────────────────────────
48
+ # Resolved BEFORE sourcing .env.agent.<id>, which overrides REPO_ROOT with the
49
+ # worktree path — artifacts must land in the main repo root per convention.
50
+ ARTIFACT_DIR="$REPO_ROOT/.har/artifacts/secrets-scan"
51
+ mkdir -p "$ARTIFACT_DIR"
52
+ REPORT_PATH="$ARTIFACT_DIR/report.json"
53
+ SCAN_LOG="$ARTIFACT_DIR/gitleaks.log"
54
+
55
+ # ── Resolve agent env ─────────────────────────────────────────────────────────
56
+ ENV_FILE="$(resolve_agent_env_file "$AGENT_ID" "$REPO_ROOT")" || {
57
+ echo "No .env.agent.${AGENT_ID} found." >&2
58
+ har_suggest_launch "$AGENT_ID" >&2
59
+ exit 1
60
+ }
61
+
62
+ set -a
63
+ # shellcheck source=/dev/null
64
+ source "$ENV_FILE"
65
+ set +a
66
+
67
+ WORK_DIR="$(resolve_agent_work_dir "$ENV_FILE")"
68
+
69
+ GITLEAKS_VERSION="$(gitleaks version 2>/dev/null | head -1 || echo unknown)"
70
+ log "gitleaks ${GITLEAKS_VERSION} — ${MODE} scan of $WORK_DIR"
71
+
72
+ # ── Scan ──────────────────────────────────────────────────────────────────────
73
+ # --exit-code 99 distinguishes "leaks found" (99) from tool errors (other non-zero).
74
+ # --redact keeps discovered secret values out of the report artifact.
75
+ START=$(now_ms)
76
+
77
+ set +e
78
+ gitleaks "$MODE" "$WORK_DIR" \
79
+ --report-format json \
80
+ --report-path "$REPORT_PATH" \
81
+ --exit-code 99 \
82
+ --redact \
83
+ --no-banner \
84
+ >"$SCAN_LOG" 2>&1
85
+ SCAN_EXIT=$?
86
+ set -e
87
+
88
+ END=$(now_ms)
89
+ TOTAL_MS=$(( END - START ))
90
+
91
+ if [ "$SCAN_EXIT" != "0" ] && [ "$SCAN_EXIT" != "99" ]; then
92
+ log "gitleaks failed (exit $SCAN_EXIT) — last log lines:"
93
+ tail -20 "$SCAN_LOG" | sed 's/^/ /' >&2
94
+ fi
95
+
96
+ if [ "$SCAN_EXIT" = "99" ]; then
97
+ log "Leaks detected — see $REPORT_PATH (redacted)"
98
+ else
99
+ log "Scan finished in ${TOTAL_MS}ms (exit $SCAN_EXIT)"
100
+ fi
101
+
102
+ # ── Output ────────────────────────────────────────────────────────────────────
103
+ REPORT_PATH="$REPORT_PATH" SCAN_EXIT="$SCAN_EXIT" TOTAL_MS="$TOTAL_MS" \
104
+ AGENT_ID="$AGENT_ID" MODE="$MODE" node -e "
105
+ const fs = require('fs');
106
+ const scanExit = Number(process.env.SCAN_EXIT);
107
+ let leaks = [];
108
+ try {
109
+ leaks = JSON.parse(fs.readFileSync(process.env.REPORT_PATH, 'utf8')) || [];
110
+ } catch { /* no report written (older gitleaks writes none on a clean scan) */ }
111
+ const status = scanExit === 0 ? 'pass' : 'fail';
112
+ const out = {
113
+ status,
114
+ stageId: 'secrets-scan',
115
+ kind: 'test',
116
+ agent_id: Number(process.env.AGENT_ID),
117
+ total_ms: Number(process.env.TOTAL_MS),
118
+ mode: process.env.MODE,
119
+ leaks_found: leaks.length,
120
+ findings: leaks.slice(0, 20).map((l) => ({
121
+ rule: l.RuleID,
122
+ file: l.File,
123
+ line: l.StartLine,
124
+ commit: l.Commit || undefined,
125
+ })),
126
+ error: scanExit !== 0 && scanExit !== 99 ? 'gitleaks exited ' + scanExit + ' — see .har/artifacts/secrets-scan/gitleaks.log' : undefined,
127
+ artifacts: [
128
+ { path: '.har/artifacts/secrets-scan', kind: 'directory' }
129
+ ]
130
+ };
131
+ process.stdout.write(JSON.stringify(out, null, 2) + '\n');
132
+ "
133
+
134
+ if [ "$SCAN_EXIT" = "99" ]; then
135
+ exit 1
136
+ fi
137
+ exit "$SCAN_EXIT"
@@ -0,0 +1,34 @@
1
+ # Gitleaks plugin
2
+
3
+ Installs a `secrets-scan` stage that runs [Gitleaks](https://github.com/gitleaks/gitleaks)
4
+ against the agent work dir, so hardcoded credentials fail verification before
5
+ they reach the default branch.
6
+
7
+ ```bash
8
+ har env add-plugin gitleaks
9
+ ```
10
+
11
+ What it adds:
12
+
13
+ - `.har/stages/secrets-scan.sh` — the stage script (registered in `.har/stages.json`
14
+ and appended to `verificationStages`)
15
+ - `.har/stages/GITLEAKS.md` — adaptation guide
16
+ - `.gitleaks.toml` — default config extending the built-in ruleset with harness
17
+ allowlists (skipped if the repo already has one)
18
+ - `.github/workflows/gitleaks.yml` — official `gitleaks/gitleaks-action` CI
19
+ workflow (skip with `--skip-ci`)
20
+
21
+ Requirements: the `gitleaks` binary on PATH (`brew install gitleaks` or a
22
+ [release binary](https://github.com/gitleaks/gitleaks/releases)). No package.json
23
+ changes — Gitleaks is an external tool, like RocketSim.
24
+
25
+ Run it:
26
+
27
+ ```bash
28
+ ./.har/stages/secrets-scan.sh 1 # scan the working tree (default)
29
+ ./.har/stages/secrets-scan.sh 1 git # scan full git history
30
+ ```
31
+
32
+ Findings land in `.har/artifacts/secrets-scan/report.json` (secret values
33
+ redacted). See `.har/stages/GITLEAKS.md` for tuning allowlists, baselines for
34
+ noisy history, and how the CI workflow feeds compliance platforms like Vanta.
@@ -0,0 +1,37 @@
1
+ {
2
+ "id": "gitleaks",
3
+ "stageId": "secrets-scan",
4
+ "verificationStages": [
5
+ "secrets-scan"
6
+ ],
7
+ "stage": {
8
+ "id": "secrets-scan",
9
+ "kind": "test",
10
+ "description": "Gitleaks secrets scan (working tree by default; pass 'git' to scan history)",
11
+ "script": "stages/secrets-scan.sh",
12
+ "requiresAgentId": true,
13
+ "artifacts": [
14
+ {
15
+ "path": ".har/artifacts/secrets-scan",
16
+ "kind": "directory",
17
+ "description": "Redacted JSON findings report and scan log"
18
+ }
19
+ ]
20
+ },
21
+ "files": [
22
+ { "src": ".har/stages/secrets-scan.sh", "dest": ".har/stages/secrets-scan.sh", "executable": true },
23
+ { "src": ".har/stages/GITLEAKS.md", "dest": ".har/stages/GITLEAKS.md" }
24
+ ],
25
+ "optionalFiles": [
26
+ { "src": ".gitleaks.toml", "dest": ".gitleaks.toml" },
27
+ { "src": ".github/workflows/gitleaks.yml", "dest": ".github/workflows/gitleaks.yml", "skipFlag": "skipCi" }
28
+ ],
29
+ "nextSteps": [
30
+ "Install gitleaks: brew install gitleaks — or a release binary from https://github.com/gitleaks/gitleaks/releases",
31
+ "./.har/launch.sh 1",
32
+ "./.har/stages/secrets-scan.sh 1",
33
+ "Open .har/artifacts/secrets-scan/report.json for findings (secrets are redacted)",
34
+ "Tune allowlists in .gitleaks.toml — read .har/stages/GITLEAKS.md for the adaptation guide"
35
+ ],
36
+ "docsPath": ".har/stages/GITLEAKS.md"
37
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osfactory/har",
3
- "version": "0.51.0",
3
+ "version": "0.52.0",
4
4
  "description": "Open harness for reproducible multi-agent coding workflows",
5
5
  "keywords": [
6
6
  "har",