Skip to content

Commit 05cdc36

Browse files
authored
Merge pull request #4 from Coding-Autopilot-System/hardening/enterprise-audit-20260610
feat: harden deterministic CI repair demo
2 parents f57d500 + 060186b commit 05cdc36

18 files changed

Lines changed: 259 additions & 20 deletions

.github/workflows/autopilot-create-issue.yml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
name: Autopilot Issue Intake
1+
name: Autopilot Issue Intake
22

33
on:
44
workflow_run:
55
# Update this list in each repo to match the workflows you want monitored.
66
workflows: ["Demo CI"]
77
types: [completed]
88

9+
concurrency:
10+
group: autopilot-intake-${{ github.event.workflow_run.head_sha }}
11+
cancel-in-progress: false
12+
913
permissions:
1014
actions: read
1115
issues: write
@@ -15,9 +19,10 @@ jobs:
1519
create-issue:
1620
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
1721
runs-on: ubuntu-latest
22+
timeout-minutes: 5
1823
steps:
1924
- name: Create or update issue
20-
uses: actions/github-script@v7
25+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
2126
with:
2227
script: |
2328
const run = context.payload.workflow_run;
@@ -57,6 +62,10 @@ jobs:
5762
`Branch: ${run.head_branch}`,
5863
`SHA: ${run.head_sha}`,
5964
`Run: ${run.html_url}`,
65+
`Attempt: ${run.run_attempt}`,
66+
`Event: ${run.event}`,
67+
`Actor: ${run.actor?.login || 'unknown'}`,
68+
`Conclusion: ${run.conclusion}`,
6069
'',
6170
'Failed steps:',
6271
stepSummary,
@@ -92,6 +101,7 @@ jobs:
92101
owner,
93102
repo,
94103
issue_number: issue.number,
104+
state: 'open',
95105
body,
96106
});
97107
await github.rest.issues.addLabels({

.github/workflows/ci.yml

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,40 @@
1-
name: CI
1+
name: CI
22

33
on:
44
push:
55
branches: [main]
66
pull_request:
77
branches: [main]
88

9+
permissions:
10+
contents: read
11+
912
jobs:
1013
validate:
1114
runs-on: ubuntu-latest
15+
timeout-minutes: 5
1216
steps:
13-
- uses: actions/checkout@v4
17+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
18+
19+
- name: Install validation dependencies
20+
run: python -m pip install --requirement requirements-dev.txt
1421

1522
- name: Validate workflow YAML
23+
shell: python
1624
run: |
17-
python -c "
18-
import yaml, glob
19-
files = glob.glob('.github/workflows/*.yml')
20-
errors = []
21-
for f in files:
22-
try:
23-
with open(f) as fh:
24-
yaml.safe_load(fh)
25-
print(' OK:', f)
26-
except yaml.YAMLError as e:
27-
print(' WARN:', f, '-', str(e).split('\n')[0])
28-
print('Validated', len(files), 'workflow files')
29-
"
25+
import pathlib
26+
import yaml
27+
28+
files = sorted(pathlib.Path('.github/workflows').glob('*.yml'))
29+
if not files:
30+
raise SystemExit('No workflow files found')
31+
32+
for path in files:
33+
with path.open(encoding='utf-8') as stream:
34+
yaml.safe_load(stream)
35+
print(f'OK: {path}')
36+
37+
print(f'Validated {len(files)} workflow files')
38+
39+
- name: Run workflow contract tests
40+
run: python -m unittest discover -s tests -v

.github/workflows/demo-ci.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
1-
name: Demo CI
1+
name: Demo CI
22

33
on:
44
workflow_dispatch:
5+
inputs:
6+
simulate_failure:
7+
description: "Fail the demo job to exercise Autopilot intake"
8+
required: true
9+
type: boolean
10+
default: false
511
push:
612
branches: [main]
713

14+
permissions:
15+
contents: read
16+
817
jobs:
918
demo:
1019
runs-on: ubuntu-latest
20+
timeout-minutes: 5
1121
steps:
1222
- name: Demo sanity
1323
run: |
1424
echo "Simulated demo step (non-blocking)."
25+
26+
- name: Simulate repairable failure
27+
if: ${{ inputs.simulate_failure }}
28+
run: |
29+
echo "Intentional demo failure requested."
30+
exit 1

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
__pycache__/
2+
*.py[cod]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Enterprise Hardening Summary
2+
3+
The GSD audit classified eight findings as auto-fixable and two GitHub administration items as manual-only. All eight repository findings were fixed, tested, and recorded in `memory/examples/`.
4+
5+
The demo now provides a deliberate failure switch, strict CI validation, immutable Action references, least-privilege workflow boundaries, executable workflow contracts, serialized intake, richer audit evidence, and a repeatable operator runbook.
6+
7+
F-08 failed its first contract test because the intake update path did not reopen closed issues. That attempt was reverted, corrected, and verified on retry.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Enterprise Hardening UAT
2+
3+
**Date:** 2026-06-10
4+
**Source:** `gsd-audit-fix --severity all --max 8`
5+
**Scope:** demo reproducibility, security, tests, CI, user journey, failure modes, and docs
6+
7+
## Classification
8+
9+
| ID | Severity | Classification | Finding | Files |
10+
|---|---|---|---|---|
11+
| F-01 | high | auto-fixable | The documented demo cannot produce a failure because Demo CI always succeeds. | `.github/workflows/demo-ci.yml`, `README.md` |
12+
| F-02 | high | auto-fixable | CI prints YAML parse warnings but still exits successfully. | `.github/workflows/ci.yml` |
13+
| F-03 | high | auto-fixable | Third-party Actions use mutable major-version tags instead of immutable commit SHAs. | `.github/workflows/ci.yml`, `.github/workflows/autopilot-create-issue.yml` |
14+
| F-04 | medium | auto-fixable | CI and Demo CI do not declare least-privilege token permissions or job timeouts. | `.github/workflows/ci.yml`, `.github/workflows/demo-ci.yml` |
15+
| F-05 | medium | auto-fixable | No automated contract tests protect workflow behavior and security invariants. | `tests/test_workflows.py`, `.github/workflows/ci.yml` |
16+
| F-06 | medium | auto-fixable | Intake processing has no concurrency guard or timeout, allowing duplicate/racing issue updates. | `.github/workflows/autopilot-create-issue.yml` |
17+
| F-07 | low | auto-fixable | Intake issues omit run attempt, event, actor, and failure conclusion from the audit evidence. | `.github/workflows/autopilot-create-issue.yml` |
18+
| F-08 | low | auto-fixable | The demo runbook lacks prerequisites, reset steps, and failure-mode troubleshooting; repeat demonstrations can leave a matching intake issue closed. | `.github/workflows/autopilot-create-issue.yml`, `README.md` |
19+
20+
## Manual-only Findings
21+
22+
- M-01: Protect `main` and require the `CI` status check. The GitHub API reports that `main` is not protected.
23+
- M-02: Configure the organization Actions policy to allow only approved actions and require immutable SHA pinning where supported. The current GitHub token cannot read or change this setting.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Enterprise Hardening Verification
2+
3+
**Date:** 2026-06-10
4+
**Branch:** `hardening/enterprise-audit-20260610`
5+
**Result:** passed with manual GitHub administration gaps
6+
7+
## Finding Status
8+
9+
| ID | Result | Evidence |
10+
|---|---|---|
11+
| F-01 | passed | `simulate_failure` is explicit and defaults to false |
12+
| F-02 | passed | invalid YAML now fails CI; dependency is pinned |
13+
| F-03 | passed | third-party Actions use verified 40-character commit SHAs |
14+
| F-04 | passed | routine jobs declare read-only permissions and five-minute timeouts |
15+
| F-05 | passed | seven workflow contract tests run in CI; bytecode is ignored |
16+
| F-06 | passed | intake updates are serialized by head SHA and time-bounded |
17+
| F-07 | passed | issues record attempt, event, actor, and conclusion |
18+
| F-08 | passed after one reverted attempt | matching closed issues reopen; runbook covers prerequisites, reset, and troubleshooting |
19+
20+
## Verification Commands
21+
22+
- `python -m unittest discover -s tests -v`: 7 passed
23+
- strict PyYAML parse of `.github/workflows/*.yml`: 3 validated
24+
- PowerShell parser check of `scripts/record-fix.ps1`: passed
25+
- `git diff --check origin/main...HEAD`: passed
26+
- clean worktree after tests: passed
27+
28+
## Manual Gaps
29+
30+
- Protect `main` and require the `CI` status check.
31+
- Configure the organization Actions allow-list and immutable pinning policy.
32+
- Run the live failure-to-issue-to-repair journey after this branch is merged because `workflow_dispatch` uses the default-branch workflow definition.
33+
- Install `actionlint` in the workstation bootstrap and add it to CI; it was not available for this verification.

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# autopilot-demo
1+
# autopilot-demo
22

33
[![CI](https://github.com/Coding-Autopilot-System/autopilot-demo/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/Coding-Autopilot-System/autopilot-demo/actions/workflows/ci.yml)
44
[![Demo CI](https://github.com/Coding-Autopilot-System/autopilot-demo/actions/workflows/demo-ci.yml/badge.svg?branch=main)](https://github.com/Coding-Autopilot-System/autopilot-demo/actions/workflows/demo-ci.yml)
@@ -47,7 +47,7 @@ gh pr list -R Coding-Autopilot-System/autopilot-demo
4747

4848
## Demo runbook
4949

50-
1. Trigger [`.github/workflows/demo-ci.yml`](.github/workflows/demo-ci.yml) to produce a known failure signal.
50+
1. Trigger [`.github/workflows/demo-ci.yml`](.github/workflows/demo-ci.yml) with `simulate_failure=true` to produce a known failure signal. Pushes and default dispatches remain green.
5151
2. Confirm [`.github/workflows/autopilot-create-issue.yml`](.github/workflows/autopilot-create-issue.yml) creates an `autofix + queued` issue.
5252
3. Watch `autopilot-core` pick up the issue and open a PR back into this repo.
5353
4. Use this repo's issue, branch, and PR history as the audit trail for the demo.
@@ -72,3 +72,16 @@ gh pr list -R Coding-Autopilot-System/autopilot-demo
7272
- [autopilot-core](https://github.com/Coding-Autopilot-System/autopilot-core) - operator control plane
7373
- [ci-autopilot](https://github.com/Coding-Autopilot-System/ci-autopilot) - worker/runtime reference
7474
- [Coding-Autopilot-System org](https://github.com/Coding-Autopilot-System)
75+
## Prerequisites and expected result
76+
77+
- Authenticate GitHub CLI with `gh auth status` and confirm Actions are enabled for this repository.
78+
- Run the `autopilot-core` operator with access to this repository before triggering the failure.
79+
- Expect Demo CI to fail, Autopilot Issue Intake to create or reopen one `autofix + queued` issue, and the operator to propose a pull request.
80+
81+
## Reset and troubleshooting
82+
83+
1. Close the completed intake issue and merge or close its repair pull request before the next demonstration.
84+
2. Re-run with `simulate_failure=true`; intake reopens the matching issue when the same commit is demonstrated again.
85+
3. If no issue appears, inspect `gh run list -R Coding-Autopilot-System/autopilot-demo --workflow autopilot-create-issue.yml` and confirm the failed run was named `Demo CI`.
86+
4. If the issue remains queued, verify the `autopilot-core` operator is running and can read issues and create branches and pull requests in this repository.
87+
5. If CI fails before the demo step, run `python -m unittest discover -s tests -v` locally and repair the workflow contract violation first.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# F-01 reproducible demo failure
2+
3+
Issue Description: The documented demo could not produce a failure because Demo CI always succeeded.
4+
State: Pushes and manual dispatches both ran only a non-blocking step.
5+
Action: Added an explicit `simulate_failure` dispatch input and documented the required command.
6+
Result: Operators can intentionally exercise intake while normal pushes and default dispatches stay green.
7+
Diff Patch: Updated `.github/workflows/demo-ci.yml` and `README.md`.
8+
Rationale: A demo repair pipeline must expose a safe, deliberate, and reproducible failure path.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# F-02 strict YAML validation
2+
3+
Issue Description: CI printed YAML parsing warnings but always returned success.
4+
State: Invalid workflow YAML could pass the portfolio CI check.
5+
Action: Made parsing errors fatal and pinned the YAML parser dependency.
6+
Result: CI now fails closed when workflow YAML is missing or invalid.
7+
Diff Patch: Updated `.github/workflows/ci.yml` and added `requirements-dev.txt`.
8+
Rationale: Validation jobs must fail on the condition they claim to validate.

0 commit comments

Comments
 (0)