From 118aca86dbbbe5551f472ec097ff170b51ac187f Mon Sep 17 00:00:00 2001 From: "Jason Lee (Titan Zero)" Date: Sun, 4 Oct 2026 15:21:34 +1100 Subject: [PATCH 1/2] ci: add tracked secret hygiene check --- .github/workflows/no-secrets.yml | 27 ++++++++++ docs/ENGINE_IMPLEMENTATION_AUDIT.md | 6 +++ scripts/no-secrets-check.php | 76 +++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100644 .github/workflows/no-secrets.yml create mode 100644 scripts/no-secrets-check.php diff --git a/.github/workflows/no-secrets.yml b/.github/workflows/no-secrets.yml new file mode 100644 index 0000000..d31769c --- /dev/null +++ b/.github/workflows/no-secrets.yml @@ -0,0 +1,27 @@ +name: Tracked Secret Hygiene + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: secret-hygiene-\${{ github.workflow }}-\${{ github.ref }} + cancel-in-progress: true + +jobs: + secret-scan: + name: Scan tracked text files + runs-on: ubuntu-latest + steps: + - name: Check out source + uses: actions/checkout@v4 + + - name: Scan for secret-like values + shell: bash + run: php scripts/no-secrets-check.php diff --git a/docs/ENGINE_IMPLEMENTATION_AUDIT.md b/docs/ENGINE_IMPLEMENTATION_AUDIT.md index 50b5fcd..83983e9 100644 --- a/docs/ENGINE_IMPLEMENTATION_AUDIT.md +++ b/docs/ENGINE_IMPLEMENTATION_AUDIT.md @@ -51,6 +51,12 @@ The 31-case policy result currently linked from the README is historical evidenc Legal provenance is also unresolved on current `main`: the root `LICENSE` path is absent, and GitHub reports no repository license. The README's proprietary-license statement remains the only checked-in guidance. This audit does not invent an MIT or other license; PR #6 proposes a license change and should be resolved by its owner before any legal claim is published. Preserve existing attribution and history until that choice is merged. +## Tracked configuration and secret scan + +The repository currently has no tracked `.env` or `.env.*` files; `.gitignore` excludes runtime environment files while allowing future redacted `.env.example` templates. The new `scripts/no-secrets-check.php` scans Git-tracked text files and reports only path, line, and rule identifiers—never matched values. It rejects private-key markers, common provider/GitHub/AWS token formats, and credential-like assignments. + +The sole allowlisted match is the deterministic evaluator fixture `interaction-policy-eval-secret-2026` in `scripts/authority-policy-eval.php`; it is not a runtime credential and is matched by exact path and literal. The [tracked secret hygiene workflow](../.github/workflows/no-secrets.yml) runs the check on pull requests and pushes to `main`. Branch-protection required status is not asserted here and must be verified separately before relying on it as a merge gate. + ## Recommended next work Implement each no-op method only with its owning contract's intended semantics and a focused test. Until then, keep the methods visible as compatibility scaffolds and keep portfolio language at the deterministic baseline level recorded in [AI_ENGINEERING.md](AI_ENGINEERING.md). diff --git a/scripts/no-secrets-check.php b/scripts/no-secrets-check.php new file mode 100644 index 0000000..6af11f3 --- /dev/null +++ b/scripts/no-secrets-check.php @@ -0,0 +1,76 @@ + $path !== '')); +$rules = [ + 'private-key' => '/-----BEGIN [^-]+ PRIVATE KEY-----/', + 'known-token' => '/(? '/(? '/\bAKIA[0-9A-Z]{16}\b/', + 'credential-assignment' => "/\b(?:api[_-]?key|secret|password|token)\b\s*[:=]\s*[\"']?([A-Za-z0-9_\/.=+\-]{12,})/i", +]; +$allowlistedFixtures = [ + 'scripts/authority-policy-eval.php' => 'interaction-policy-eval-secret-2026', +]; + +$findings = []; +$allowlistedMatches = 0; +$textFileCount = 0; + +foreach ($trackedFiles as $relativePath) { + $absolutePath = $root . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $relativePath); + if (!is_file($absolutePath)) { + continue; + } + + $contents = file_get_contents($absolutePath); + if (!is_string($contents) || str_contains($contents, "\0")) { + continue; + } + $textFileCount++; + + foreach ($rules as $rule => $pattern) { + $matches = []; + if (preg_match_all($pattern, $contents, $matches, PREG_OFFSET_CAPTURE) !== 1) { + continue; + } + + foreach ($matches[0] as $match) { + $value = (string) $match[0]; + $offset = (int) $match[1]; + $line = 1 + substr_count(substr($contents, 0, $offset), "\n"); + $prefix = substr($contents, 0, $offset + strlen($value)); + $lines = explode("\n", $prefix); + $lineText = (string) ($lines[array_key_last($lines)] ?? ''); + $isAllowlistedFixture = $rule === 'credential-assignment' + && isset($allowlistedFixtures[$relativePath]) + && str_contains($lineText, $allowlistedFixtures[$relativePath]); + + if ($isAllowlistedFixture) { + $allowlistedMatches++; + continue; + } + + $findings[$relativePath . ':' . $line . ':' . $rule] = true; + } + } +} + +if ($findings !== []) { + ksort($findings); + fwrite(STDERR, "Secret-like values detected (values redacted):\n"); + foreach (array_keys($findings) as $finding) { + fwrite(STDERR, " - {$finding}\n"); + } + exit(1); +} + +echo "No secret-like values found in {$textFileCount} tracked text files; allowlisted deterministic fixture matches: {$allowlistedMatches}.\n"; From 0efcf9835e565e7b4fef853f041577bb61ca9386 Mon Sep 17 00:00:00 2001 From: "Jason Lee (Titan Zero)" Date: Sun, 4 Oct 2026 15:22:22 +1100 Subject: [PATCH 2/2] fix: harden secret scan findings --- .github/workflows/no-secrets.yml | 2 +- scripts/no-secrets-check.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/no-secrets.yml b/.github/workflows/no-secrets.yml index d31769c..cc6e028 100644 --- a/.github/workflows/no-secrets.yml +++ b/.github/workflows/no-secrets.yml @@ -11,7 +11,7 @@ permissions: contents: read concurrency: - group: secret-hygiene-\${{ github.workflow }}-\${{ github.ref }} + group: secret-hygiene-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: diff --git a/scripts/no-secrets-check.php b/scripts/no-secrets-check.php index 6af11f3..4f56734 100644 --- a/scripts/no-secrets-check.php +++ b/scripts/no-secrets-check.php @@ -39,7 +39,7 @@ foreach ($rules as $rule => $pattern) { $matches = []; - if (preg_match_all($pattern, $contents, $matches, PREG_OFFSET_CAPTURE) !== 1) { + if (preg_match_all($pattern, $contents, $matches, PREG_OFFSET_CAPTURE) === false || $matches[0] === []) { continue; }