ci(security): phase-1 CI hardening — affected-area tests, least privilege, action pinning, dependency governance (#336)

* ci(security): run deterministic eval tests in affected-area CI (Task 04)

The build-check job validated build + suite structure but never ran the
tests, and its summary referenced a `test:ci` script that did not exist.
Make affected-area CI meaningful:

- Add `test:ci` to evals/framework running the offline, deterministic
  Vitest allowlist (7 files / 112 tests) — no model, network, or paid
  execution.
- Add a required "Run deterministic tests" step to build-check; a failure
  fails the job and the existing PR summary gate (which keys on
  build-check.result) fails closed.
- Correct the summary note to state test:ci runs the deterministic
  allowlist and that model/network agent suites are excluded on PRs.

The broader deterministic suite has 3 pre-existing failing files
(framework-confidence, logger, test-runner; confirmed failing before this
work) which are intentionally out of the allowlist and tracked separately.

Validated locally: build, validate:suites:all, and test:ci all exit 0.

* ci(security): least privilege permissions + pin actions to SHAs (Task 05)

Harden all 9 GitHub Actions workflows:

Least privilege:
- Add explicit top-level `permissions: contents: read` to installer-checks,
  validate-test-suites, and opencode (opencode's job keeps the writes it
  needs; the top level now defaults to read).
- Every workflow now declares an explicit top-level permissions block.
- Write scopes retained only where justified (releases, doc/registry
  commits, follow-up PRs, and sync-docs' issues.create).

Immutable action pinning:
- Pin every `uses:` to a full 40-char commit SHA with a version comment,
  including first-party actions/* (checkout, github-script, setup-node,
  upload-artifact) and third-party (oven-sh/setup-bun).
- Replace the two mutable refs that could change under us at any push:
  ludeeus/action-shellcheck@master and sst/opencode/github@latest.

Record all SHAs, versions, and permission justifications in
docs/maintenance/repository-recovery/action-pin-inventory.md.

Verified: all 9 workflows parse as valid YAML; no floating tag/branch refs
remain; every workflow has a top-level permissions block.

* docs(security): add SECURITY.md and private-reporting checklist (Task 06)

- Add root SECURITY.md: supported versions (0.7.x), private reporting via
  GitHub's "Report a vulnerability", best-effort response expectations,
  coordinated disclosure, and no-secret guidance.
- Add private-vulnerability-reporting checklist that separates repository
  file work (this PR) from GitHub settings changes that require their own
  approval (Task 07: enabling private vulnerability reporting).

No external links to validate; the reporting path uses the repo Security
tab. SECURITY.md documents the private reporting path ahead of Task 07
enabling it.

* ci(security): add dependency governance and ownership controls (Task 08)

- .github/dependabot.yml: weekly grouped github-actions updates (keeps the
  Task 05 SHA pins current). Scoped to actions only — the primary lockfile
  is bun.lock and Dependabot's npm ecosystem would desync it; npm
  dependency risk is covered by dependency-review below.
- .github/workflows/dependency-review.yml: runs on PRs with contents: read,
  SHA-pinned actions, fail-on-severity: high to block newly introduced
  high-severity vulnerabilities (exceptions documented inline).
- .github/CODEOWNERS: default owner @darrenhinde with explicit ownership of
  security-sensitive paths (workflows, dependabot, CODEOWNERS, SECURITY.md,
  scripts/validation).

Verified: dependabot.yml and dependency-review.yml are valid YAML;
dependency-review actions are SHA-pinned with contents: read; CODEOWNERS
owner is the repository owner.

* docs(security): record GitHub security settings evidence (Task 07)

Enable private vulnerability reporting and record read-back evidence.

Settings changed (each approved immediately before, verified by read-back):
- Private vulnerability reporting: enabled=false -> enabled=true. The
  Security tab now offers "Report a vulnerability", making the path
  documented in SECURITY.md live.
- Dependency Graph / Dependabot alerts: 404 -> 204. This was an
  undocumented prerequisite of Task 08's dependency-review.yml, which
  failed with "Dependency graph is not enabled"; the Dependency Review
  check on PR #336 went fail -> pass after enabling it.

No other repository setting was modified; secret scanning and push
protection are unchanged, and dependabot_security_updates remains disabled
(out of scope, would need its own approval). Both changes are reversible
via the corresponding DELETE calls.

Marks Part B of the private-vulnerability-reporting checklist complete.
This commit is contained in:
Darren Hinde 2026-07-15 00:19:28 +01:00 committed by GitHub
parent 926d68de93
commit 699b2d7769
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 331 additions and 35 deletions

19
.github/CODEOWNERS vendored Normal file
View file

@ -0,0 +1,19 @@
# Code owners for OpenAgentsControl
#
# Owners are automatically requested for review on PRs that touch matching
# paths. Security-sensitive paths are listed explicitly so they always require
# a maintainer review.
# Default owner for everything in the repo.
* @darrenhinde
# CI/CD workflows — untrusted-input execution surface.
/.github/workflows/ @darrenhinde
/.github/dependabot.yml @darrenhinde
/.github/CODEOWNERS @darrenhinde
# Security policy and reporting.
/SECURITY.md @darrenhinde
# PR validation and detection scripts consumed by CI.
/scripts/validation/ @darrenhinde

19
.github/dependabot.yml vendored Normal file
View file

@ -0,0 +1,19 @@
version: 2
updates:
# GitHub Actions — keeps workflow action versions (and their SHA pins) current.
# Scoped to actions only: the repo's primary lockfile is bun.lock, and
# Dependabot's npm ecosystem would update package-lock.json without syncing
# bun.lock, causing lockfile drift. Dependency (npm) vulnerabilities are
# instead caught at PR time by dependency-review.yml.
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 5
groups:
github-actions:
patterns:
- "*"
commit-message:
prefix: "ci"

View file

@ -27,13 +27,13 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with: with:
fetch-depth: 2 fetch-depth: 2
- name: Check if this was a version bump PR merge - name: Check if this was a version bump PR merge
id: check id: check
uses: actions/github-script@v7 uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with: with:
script: | script: |
const fs = require('fs'); const fs = require('fs');
@ -83,7 +83,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with: with:
fetch-depth: 0 fetch-depth: 0

26
.github/workflows/dependency-review.yml vendored Normal file
View file

@ -0,0 +1,26 @@
name: Dependency Review
on:
pull_request:
branches: [main, dev]
permissions:
contents: read
jobs:
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- name: Review dependencies
uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4
with:
# Block PRs that introduce newly known high-severity (or worse)
# vulnerabilities. Document any exception inline in the PR that adds
# an allow-ghsas / allow-dependencies-licenses entry here.
fail-on-severity: high

View file

@ -15,6 +15,9 @@ on:
- 'update.sh' - 'update.sh'
workflow_dispatch: workflow_dispatch:
permissions:
contents: read
jobs: jobs:
shellcheck: shellcheck:
name: ShellCheck Analysis name: ShellCheck Analysis
@ -22,10 +25,10 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Run ShellCheck on install.sh - name: Run ShellCheck on install.sh
uses: ludeeus/action-shellcheck@master uses: ludeeus/action-shellcheck@00b27aa7cb85167568cb48a3838b75f4265f2bca # master (resolved 2026-07-15)
with: with:
scandir: '.' scandir: '.'
additional_files: 'install.sh update.sh' additional_files: 'install.sh update.sh'
@ -43,7 +46,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Check install.sh syntax - name: Check install.sh syntax
run: bash -n install.sh run: bash -n install.sh
@ -73,7 +76,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install jq (Ubuntu) - name: Install jq (Ubuntu)
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
@ -102,7 +105,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install jq (Ubuntu) - name: Install jq (Ubuntu)
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
@ -133,7 +136,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install jq (Ubuntu) - name: Install jq (Ubuntu)
if: matrix.os == 'ubuntu-latest' if: matrix.os == 'ubuntu-latest'
@ -162,7 +165,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install dependencies - name: Install dependencies
run: sudo apt-get install -y jq curl run: sudo apt-get install -y jq curl

View file

@ -4,6 +4,9 @@ on:
issue_comment: issue_comment:
types: [created] types: [created]
permissions:
contents: read
jobs: jobs:
opencode: opencode:
if: | if: |
@ -19,12 +22,12 @@ jobs:
issues: write issues: write
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with: with:
fetch-depth: 1 fetch-depth: 1
- name: Run opencode - name: Run opencode
uses: sst/opencode/github@latest uses: sst/opencode/github@77fc88c8ade8e5a620ebbe1197f3a572d29ae91a # latest (resolved 2026-07-15)
env: env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
with: with:

View file

@ -25,13 +25,13 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with: with:
fetch-depth: 2 fetch-depth: 2
- name: Check if this was a version bump PR - name: Check if this was a version bump PR
id: check_pr_labels id: check_pr_labels
uses: actions/github-script@v7 uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with: with:
script: | script: |
// Get the commit that triggered this workflow // Get the commit that triggered this workflow
@ -106,12 +106,12 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version: '20' node-version: '20'

View file

@ -18,7 +18,7 @@ jobs:
steps: steps:
- name: Check PR title format - name: Check PR title format
id: validate id: validate
uses: actions/github-script@v7 uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with: with:
script: | script: |
const prTitle = context.payload.pull_request.title; const prTitle = context.payload.pull_request.title;
@ -163,7 +163,7 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with: with:
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
@ -192,12 +192,12 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with: with:
persist-credentials: false persist-credentials: false
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version: '20' node-version: '20'
cache: 'npm' cache: 'npm'
@ -215,6 +215,10 @@ jobs:
working-directory: evals/framework working-directory: evals/framework
run: npm run validate:suites:all run: npm run validate:suites:all
- name: Run deterministic tests
working-directory: evals/framework
run: npm run test:ci
- name: Summary - name: Summary
if: success() if: success()
run: | run: |
@ -222,9 +226,10 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "- ✅ TypeScript compilation successful" >> $GITHUB_STEP_SUMMARY echo "- ✅ TypeScript compilation successful" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Test suite validation passed" >> $GITHUB_STEP_SUMMARY echo "- ✅ Test suite validation passed" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Deterministic tests passed (\`npm run test:ci\`)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Note:** Full agent tests are not run on PRs to save time and costs." >> $GITHUB_STEP_SUMMARY echo "**Note:** \`test:ci\` runs the offline, deterministic Vitest allowlist only." >> $GITHUB_STEP_SUMMARY
echo "Maintainers can run \`npm run test:ci\` locally if needed." >> $GITHUB_STEP_SUMMARY echo "Model- or network-dependent agent tests (\`eval:sdk\`, integration suites) are not run on PRs." >> $GITHUB_STEP_SUMMARY
- name: Failure summary - name: Failure summary
if: failure() if: failure()

View file

@ -32,7 +32,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with: with:
fetch-depth: 2 fetch-depth: 2
@ -87,7 +87,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with: with:
fetch-depth: 0 fetch-depth: 0
@ -105,7 +105,7 @@ jobs:
- name: Create sync issue for OpenCode - name: Create sync issue for OpenCode
id: create_issue id: create_issue
uses: actions/github-script@v7 uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with: with:
script: | script: |
const issue = await github.rest.issues.create({ const issue = await github.rest.issues.create({
@ -195,7 +195,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Delete branch if created - name: Delete branch if created
run: | run: |
@ -207,7 +207,7 @@ jobs:
- name: Comment on issue - name: Comment on issue
if: needs.sync-documentation.outputs.issue_number if: needs.sync-documentation.outputs.issue_number
uses: actions/github-script@v7 uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with: with:
script: | script: |
await github.rest.issues.createComment({ await github.rest.issues.createComment({

View file

@ -18,7 +18,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with: with:
fetch-depth: 0 fetch-depth: 0

View file

@ -21,7 +21,7 @@ jobs:
steps: steps:
- name: Checkout code without persisted credentials - name: Checkout code without persisted credentials
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with: with:
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
@ -32,7 +32,7 @@ jobs:
sudo apt-get install -y jq sudo apt-get install -y jq
- name: Install Bun - name: Install Bun
uses: oven-sh/setup-bun@v2 uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with: with:
bun-version: latest bun-version: latest

View file

@ -15,6 +15,9 @@ on:
- '.github/workflows/validate-test-suites.yml' - '.github/workflows/validate-test-suites.yml'
workflow_dispatch: workflow_dispatch:
permissions:
contents: read
jobs: jobs:
validate: validate:
name: Validate Test Suite Definitions name: Validate Test Suite Definitions
@ -22,10 +25,10 @@ jobs:
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with: with:
node-version: '20' node-version: '20'
cache: 'npm' cache: 'npm'
@ -42,7 +45,7 @@ jobs:
- name: Comment on PR (if validation failed) - name: Comment on PR (if validation failed)
if: failure() && github.event_name == 'pull_request' if: failure() && github.event_name == 'pull_request'
uses: actions/github-script@v7 uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with: with:
script: | script: |
github.rest.issues.createComment({ github.rest.issues.createComment({
@ -54,7 +57,7 @@ jobs:
- name: Upload validation report - name: Upload validation report
if: always() if: always()
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with: with:
name: suite-validation-report name: suite-validation-report
path: | path: |

58
SECURITY.md Normal file
View file

@ -0,0 +1,58 @@
# Security Policy
## Supported Versions
Security fixes are provided for the latest released minor version. Older
versions are not maintained; please upgrade before reporting.
| Version | Supported |
|---------|-----------|
| 0.7.x | ✅ |
| < 0.7 | ❌ |
## Reporting a Vulnerability
**Please do not report security vulnerabilities through public GitHub issues,
pull requests, or discussions.**
Report vulnerabilities privately through GitHub's built-in private vulnerability
reporting:
1. Go to the repository's **Security** tab.
2. Select **Report a vulnerability**.
3. Provide a clear description, affected versions, reproduction steps, and
potential impact.
This opens a private advisory visible only to the maintainers and to you.
### What to include
- The affected component and version.
- Steps to reproduce, or a proof of concept.
- The impact you believe the issue has.
### What not to include
- **Do not include real secrets, credentials, API keys, or access tokens** in
your report. If a secret has been exposed, say so and rotate it — do not paste
its value.
## Response Expectations
This project is maintained on a **best-effort basis**. Reports are reviewed and
addressed as maintainer availability allows; there is no guaranteed response
time. We will engage with the private advisory as we triage and work on a fix.
## Coordinated Disclosure
We follow coordinated disclosure. Please give the maintainers a reasonable
opportunity to investigate and release a fix before disclosing the issue
publicly. We will coordinate the timing and content of any public disclosure
with you through the private advisory.
## Scope
This policy covers the code in this repository. Vulnerabilities in third-party
dependencies should be reported to the respective upstream projects; if a
dependency issue affects this project specifically, you may still report it here
so we can track remediation.

View file

@ -0,0 +1,53 @@
# GitHub Actions Pin & Permissions Inventory
_Repository-recovery Task 05 — least privilege + immutable action pinning._
_Resolved: 2026-07-15._
## Third-party / external action pins
Every `uses:` reference is pinned to a full 40-character commit SHA, with the
human-readable version retained as a trailing comment. SHAs were resolved via
`gh api repos/<owner>/<repo>/commits/<ref>` on the date above.
| Action | Previous ref | Pinned SHA | Note |
|--------|--------------|------------|------|
| `actions/checkout` | `@v4` (19 uses) | `34e114876b0b11c390a56381ad16ebd13914f8d5` | GitHub-owned |
| `actions/github-script` | `@v7` (6 uses) | `f28e40c7f34bde8b3046d885e986cb6290c5673b` | GitHub-owned |
| `actions/setup-node` | `@v4` (3 uses) | `49933ea5288caeca8642d1e84afbd3f7d6820020` | GitHub-owned |
| `actions/upload-artifact` | `@v4` (1 use) | `ea165f8d65b6e75b540449e92b4886f43607fa02` | GitHub-owned |
| `oven-sh/setup-bun` | `@v2` (1 use) | `0c5077e51419868618aeaa5fe8019c62421857d6` | Matches the SHA already pinned by the other usage |
| `ludeeus/action-shellcheck` | `@master` (1 use) | `00b27aa7cb85167568cb48a3838b75f4265f2bca` | **Was a mutable branch ref** — highest risk before pinning |
| `sst/opencode/github` | `@latest` (1 use) | `77fc88c8ade8e5a620ebbe1197f3a572d29ae91a` | **Was a mutable ref** — freezes the OpenCode agent version; update deliberately |
### Update guidance
To bump a pinned action later: re-resolve the desired tag to its SHA
(`gh api repos/<owner>/<repo>/commits/<tag> --jq .sha`), replace the SHA, and
update the trailing version comment in the same edit. Never revert a pin back to
a floating tag or branch.
## Workflow permissions (least privilege)
Every workflow now declares an explicit top-level `permissions:` block. Default
is `contents: read`; write scopes remain only where a job demonstrably needs them.
| Workflow | Top-level | Job-level writes | Justification |
|----------|-----------|------------------|---------------|
| `pr-checks.yml` | `contents: read` | — | read-only validation |
| `validate-registry.yml` | `contents: read` | — | read-only validation |
| `installer-checks.yml` | `contents: read` **(added)** | — | shellcheck / installer tests, read-only |
| `validate-test-suites.yml` | `contents: read` **(added)** | — | suite validation, read-only |
| `opencode.yml` | `contents: read` **(added)** | `id-token`, `contents`, `pull-requests`, `issues: write` (job) | `/oc` agent, gated to OWNER/MEMBER; job needs write to act on PRs/issues |
| `create-release.yml` | `contents: write` | — | creates tags/releases |
| `post-merge-pr.yml` | `contents: write`, `pull-requests: write` | — | opens follow-up PRs |
| `sync-docs.yml` | `contents: write`, `pull-requests: write`, `issues: write` | — | commits doc branch, opens PR, creates a sync issue (`issues.create`) |
| `update-registry.yml` | `contents: write` | — | commits registry updates |
`issues: write` in `sync-docs.yml` is retained because the workflow calls
`github.rest.issues.create` to open a sync-tracking issue.
## Verification
- All 9 workflow files parse as valid YAML.
- No `uses:` reference remains on a floating tag or branch — all are 40-char SHAs.
- Every workflow has an explicit top-level `permissions:` block.

View file

@ -0,0 +1,43 @@
# Private Vulnerability Reporting — Setup Checklist
_Repository-recovery Tasks 06–07. This checklist separates repository-file work
(committable in a PR) from GitHub repository-settings work (changes live GitHub
state and requires its own explicit approval)._
## Part A — Repository files (Task 06, this PR)
- [x] Publish `SECURITY.md` at the repository root with:
- [x] Supported versions.
- [x] Private reporting path (GitHub "Report a vulnerability").
- [x] Response expectations (best-effort).
- [x] Coordinated disclosure policy.
- [x] No-secret guidance.
- [x] Publish this checklist.
These are file changes only. They do **not** enable the private reporting
feature — they document how to use it once enabled.
## Part B — GitHub repository settings (Task 07, separate approval)
> ⚠️ The following change live GitHub state, not files. Each requires explicit
> approval immediately before it is made, and is verified by read-back.
- [x] Enable **Private vulnerability reporting** _(done 2026-07-15)_
- Settings → Code security and analysis → Private vulnerability reporting → Enable.
- API: `PUT /repos/{owner}/{repo}/private-vulnerability-reporting`.
- Read-back: `GET /repos/{owner}/{repo}/private-vulnerability-reporting` shows `enabled: true`. ✅
- [x] Confirm the **Security** tab now offers "Report a vulnerability" so the
path documented in `SECURITY.md` is live. ✅
- [x] Record evidence in
`docs/maintenance/repository-recovery/private-vulnerability-reporting-evidence.md`. ✅
- [x] **Dependency Graph** enabled (prerequisite discovered in Task 08 —
`dependency-review.yml` requires it). `PUT /repos/{owner}/{repo}/vulnerability-alerts`,
read-back `HTTP 204`. ✅
## Notes
- `SECURITY.md` references the private reporting path before Part B is applied.
There is a brief window where the documented path is not yet live; Part B
should follow promptly.
- No other repository setting is changed as part of Part B — only private
vulnerability reporting.

View file

@ -0,0 +1,63 @@
# GitHub Security Settings — Change Evidence
_Repository-recovery Task 07 (private vulnerability reporting), plus the
Dependency Graph prerequisite discovered during Task 08._
_Repository: `darrenhinde/OpenAgentsControl` (public). Date: 2026-07-15._
Each change below was explicitly approved immediately before it was made, and
verified by read-back. No other repository setting was modified.
## Change 1 — Dependency Graph / Dependabot alerts (Task 08 prerequisite)
Discovered while adding `dependency-review.yml`: the Dependency Review action
fails with _"Dependency review is not supported on this repository. Please ensure
that Dependency graph is enabled"_ unless the Dependency Graph is on.
| Step | Command | Result |
|------|---------|--------|
| Before | `GET /repos/darrenhinde/OpenAgentsControl/vulnerability-alerts` | `HTTP 404` (disabled) |
| Enable | `PUT /repos/darrenhinde/OpenAgentsControl/vulnerability-alerts` | `HTTP 204` |
| Read-back | `GET /repos/darrenhinde/OpenAgentsControl/vulnerability-alerts` | `HTTP 204` (enabled) |
**Verification:** the `Dependency Review` check on PR #336 went from `fail` (4s,
"Dependency graph is not enabled") to `pass` (9s) after this change.
## Change 2 — Private vulnerability reporting (Task 07)
Makes the reporting path documented in `SECURITY.md` live.
| Step | Command | Result |
|------|---------|--------|
| Before | `GET /repos/darrenhinde/OpenAgentsControl/private-vulnerability-reporting` | `{"enabled": false}` |
| Enable | `PUT /repos/darrenhinde/OpenAgentsControl/private-vulnerability-reporting` | `HTTP 204` |
| Read-back | `GET /repos/darrenhinde/OpenAgentsControl/private-vulnerability-reporting` | `{"enabled": true}` |
**Verification:** the repository Security tab now offers **Report a
vulnerability**, so the path documented in `SECURITY.md` resolves.
## Settings not changed
Confirmed unchanged before and after (`GET /repos/{owner}/{repo}` →
`security_and_analysis`):
```json
{
"dependabot_security_updates": { "status": "disabled" },
"secret_scanning": { "status": "enabled" },
"secret_scanning_non_provider_patterns": { "status": "disabled" },
"secret_scanning_push_protection": { "status": "enabled" },
"secret_scanning_validity_checks": { "status": "disabled" }
}
```
Note: `dependabot_security_updates` (automated fix PRs) remains **disabled** —
it was not in scope for Task 07 and would require its own approval. Dependabot
alerts are now on via the Dependency Graph change above; `.github/dependabot.yml`
is scoped to `github-actions` updates only.
## Reversal
Both changes are reversible with the corresponding `DELETE` calls:
- `DELETE /repos/{owner}/{repo}/private-vulnerability-reporting`
- `DELETE /repos/{owner}/{repo}/vulnerability-alerts`

View file

@ -10,6 +10,7 @@
"build:watch": "tsc --watch", "build:watch": "tsc --watch",
"test": "vitest", "test": "vitest",
"test:watch": "vitest --watch", "test:watch": "vitest --watch",
"test:ci": "vitest run src/__tests__/error-handling.test.ts src/evaluators/__tests__/evaluator-reliability.test.ts src/evaluators/__tests__/context-loading-evaluator.test.ts src/evaluators/__tests__/tool-usage-enhanced.test.ts src/sdk/__tests__/yaml-loader.test.ts src/sdk/__tests__/suite-validator.test.ts src/sdk/__tests__/validate-suites-cli.test.ts",
"test:integration": "vitest --config vitest.integration.config.ts", "test:integration": "vitest --config vitest.integration.config.ts",
"lint": "eslint src/**/*.ts", "lint": "eslint src/**/*.ts",
"lint:fix": "eslint src/**/*.ts --fix", "lint:fix": "eslint src/**/*.ts --fix",