Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
9742130
docs: plan source-authoritative Actions evidence verifier
seonghobae Aug 14, 2026
8abbf79
test(actions): define source-authoritative evidence contract
seonghobae Aug 14, 2026
7390089
feat(actions): verify source-authoritative job evidence
seonghobae Aug 14, 2026
e070342
test(actions): cover source-evidence trust boundaries
seonghobae Aug 14, 2026
e4e3380
fix(actions): reject control characters before normalization
seonghobae Aug 14, 2026
ebdc4f5
feat(actions): register evidence verifier CLI
seonghobae Aug 14, 2026
ab28ab9
fix(actions): harden bounded source-evidence validation
seonghobae Aug 14, 2026
f6e604f
test(actions): cover bounded age and identifier validation
seonghobae Aug 14, 2026
b6a6ac9
test(actions): enforce complete source-evidence docstrings
seonghobae Aug 14, 2026
9582ee8
ci(actions): require exact evidence coverage
seonghobae Aug 14, 2026
cd09d82
docs(actions): integrate source-authoritative evidence architecture
seonghobae Aug 14, 2026
55133aa
docs(actions): decide source-authoritative evidence acquisition
seonghobae Aug 14, 2026
7c4d6ba
docs(actions): index source-evidence ADR
seonghobae Aug 14, 2026
686697d
docs(actions): add buyer and operator source-evidence guide
seonghobae Aug 14, 2026
492e223
docs(actions): record source-authoritative evidence slice
seonghobae Aug 14, 2026
ca553c6
test(actions): kill source-evidence predicate mutations
seonghobae Aug 14, 2026
895f63e
ci(actions): include source-evidence mutation proof
seonghobae Aug 14, 2026
eb6f6c7
ci(actions): isolate mutation execution from coverage measurement
seonghobae Aug 14, 2026
8ca51ea
docs(actions): add source-evidence test contract
seonghobae Aug 14, 2026
c489ffb
docs(actions): model source-evidence threats
seonghobae Aug 14, 2026
0fb757f
docs(actions): add source-evidence operations
seonghobae Aug 14, 2026
4769c00
docs(actions): promote source-evidence traceability
seonghobae Aug 14, 2026
1481060
docs(prd): demote closed issue-registry prototype
seonghobae Aug 14, 2026
45e8102
test(docs): track closed issue-registry prototype truth
seonghobae Aug 14, 2026
d7c8944
test(actions): remove unused namespace import
seonghobae Aug 14, 2026
0e18941
test(actions): remove unused io import
seonghobae Aug 14, 2026
99722d8
test(actions): require terminal step evidence
seonghobae Aug 15, 2026
3929a22
fix(actions): fail closed without job steps
seonghobae Aug 15, 2026
a28bc26
test(actions): align fail-closed step coverage
seonghobae Aug 15, 2026
c1be89c
refactor(actions): reuse normalized evidence fields
seonghobae Aug 15, 2026
b3085be
test(actions): cover required-step mutation oracle
seonghobae Aug 15, 2026
64bc7e1
test(actions): make Unicode rejection lint-safe
seonghobae Aug 15, 2026
b6a076c
docs(actions): specify required step evidence tests
seonghobae Aug 15, 2026
1379343
docs(actions): sync plan with implemented evidence gates
seonghobae Aug 15, 2026
763497e
ci(actions): cover required-step regression
seonghobae Aug 15, 2026
ed0c565
test(actions): reject HTTP control characters in tokens
seonghobae Aug 15, 2026
0361805
fix(actions): reject control characters in bearer tokens
seonghobae Aug 15, 2026
8a8c0ef
docs(actions): record HTTP credential field boundary
seonghobae Aug 15, 2026
ae88ed1
chore(actions): document bearer header hardening
seonghobae Aug 15, 2026
1c85fbf
Merge branch 'develop' into feature/source-authoritative-actions-evid…
opencode-agent[bot] Aug 26, 2026
0b2774b
test(actions): reproduce repository case binding false negative
seonghobae Sep 1, 2026
e08163a
fix(actions): bind repository identity case-insensitively
seonghobae Sep 1, 2026
ccaf79a
test(actions): reproduce casing replay bypass
seonghobae Sep 1, 2026
3edce66
fix(actions): canonicalize repository evidence identity
seonghobae Sep 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions .github/workflows/github-actions-evidence-coverage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: GitHub Actions Evidence Coverage

on:
push:
branches: [develop, main]
paths:
- appguardrail_core/github_actions_evidence.py
- tests/test_github_actions_evidence.py
- tests/test_github_actions_evidence_edges.py
- tests/test_github_actions_evidence_required_steps.py
- tests/test_github_actions_evidence_validation_edges.py
- tests/test_github_actions_evidence_docstrings.py
- tests/test_github_actions_evidence_mutations.py
- .github/workflows/github-actions-evidence-coverage.yml
- requirements-test.txt
pull_request:
branches: [develop, main]
paths:
- appguardrail_core/github_actions_evidence.py
- tests/test_github_actions_evidence.py
- tests/test_github_actions_evidence_edges.py
- tests/test_github_actions_evidence_required_steps.py
- tests/test_github_actions_evidence_validation_edges.py
- tests/test_github_actions_evidence_docstrings.py
- tests/test_github_actions_evidence_mutations.py
- .github/workflows/github-actions-evidence-coverage.yml
- requirements-test.txt

permissions:
contents: read

concurrency:
group: github-actions-evidence-coverage-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
exact-coverage:
name: Source evidence statement, branch, docstring, and mutation coverage
runs-on: ubuntu-latest
timeout-minutes: 20
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
steps:
- name: Checkout exact AppGuardrail source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13'

- name: Install hash-locked test dependencies
run: >-
python -m pip install
--disable-pip-version-check
--no-cache-dir
--require-hashes
-r requirements-test.txt

- name: Checkout verified Coverage.py source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: coveragepy/coveragepy
ref: 4c0e7ff425ecbb33e2b994b41118a71eb4e39021 # 7.15.4
path: .tools/coveragepy
persist-credentials: false

- name: Run exact statement and branch coverage
env:
PYTHONPATH: ${{ github.workspace }}/.tools/coveragepy:${{ github.workspace }}
run: |
set -euo pipefail
python -m coverage erase
python -m coverage run --branch -m pytest -q \
tests/test_github_actions_evidence.py \
tests/test_github_actions_evidence_edges.py \
tests/test_github_actions_evidence_required_steps.py \
tests/test_github_actions_evidence_validation_edges.py \
tests/test_github_actions_evidence_docstrings.py
python -m coverage report \
--include='appguardrail_core/github_actions_evidence.py' \
--precision=2 \
--show-missing \
--fail-under=100

- name: Verify complete shipped-symbol docstrings independently
run: >-
python -m pytest -q
tests/test_github_actions_evidence_docstrings.py

- name: Verify production-predicate mutation resistance independently
run: >-
python -m pytest -q
tests/test_github_actions_evidence_mutations.py
31 changes: 28 additions & 3 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# AppGuardrail Architecture

**Status:** Accepted as-built/target architecture with maturity labels
**Last reviewed:** 2026-08-12
**Last reviewed:** 2026-08-14

## Architectural goal

Expand Down Expand Up @@ -61,7 +61,32 @@ flowchart LR
DET --> RES
```

A registry maps requirement identity to executable detector family; it cannot assert the detector answer. PR #911 is active-PR implementation of this contract.
A registry maps requirement identity to executable detector family; it cannot assert the detector answer. Historical PR #911 remains a non-authoritative inventory prototype. Issue #938 and PR #939 replace its broad draft with one bounded, source-authoritative detector vertical slice.

## Source-authoritative GitHub Actions evidence

```mermaid
flowchart LR
INTENT[Exact repository, run ID, job ID]
API[GitHub REST API 2022-11-28]
RUN[Authoritative workflow run object]
JOB[Authoritative workflow job object]
VALID[Identity, terminal-state, freshness validation]
HASH[Canonical SHA-256 source identity]
DECISION[Verified pass/failure evidence]

INTENT --> API
API --> RUN
API --> JOB
RUN --> VALID
JOB --> VALID
VALID --> HASH
HASH --> DECISION
```

`appguardrail_core.github_actions_evidence` is the first source-authoritative evidence acquirer. It does not accept a caller Boolean as detector truth. The production CLI fetches the exact GitHub run and job over a fixed HTTPS origin, rejects redirects and identity mismatch, caps response size, requires completed security-relevant states, rejects future/stale/duplicate evidence, and emits a bounded canonical digest. Raw logs, bearer credentials, and arbitrary cross-repository content are outside this evidence object.

This slice is an acquisition-and-verification contract, not a claim that every historical issue family is directly detected. Each future detector family must supply its own authoritative source, independent oracle, mutation evidence, and production-path proof.

## SSRF architecture

Expand Down Expand Up @@ -120,4 +145,4 @@ These modes share normalized contracts but can operate separately.

## Change control

A new detector engine, persistent schema, tenant authority, arbitrary autofix class, outbound target policy, issue-audit semantics, or automation credential boundary requires ADR and synchronized technical/security/test documentation.
A new detector engine, evidence acquirer, persistent schema, tenant authority, arbitrary autofix class, outbound target policy, issue-audit semantics, or automation credential boundary requires ADR and synchronized technical/security/test documentation.
12 changes: 12 additions & 0 deletions CHANGELOG.d/938-source-authoritative-actions-evidence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## Added

- Added `appguardrail-actions-evidence`, a source-authoritative GitHub Actions verifier that acquires exact workflow-run and workflow-job objects from the pinned GitHub REST API instead of accepting a caller-provided pass/fail assertion.
- Added immutable `ActionsJobEvidence` output with repository, run, job, commit, terminal outcome, failed-step, freshness, probe/acquirer, and SHA-256 source identity.
- Added fail-closed validation for wrong-origin URLs, identifier mismatch, malformed SHA/timestamps, incomplete states, non-security jobs, future or stale evidence, duplicates, oversized/non-JSON responses, and unavailable source data.
- Added a dedicated exact-head statement/branch coverage and complete-docstring workflow, with Coverage.py 7.15.4 pinned to verified source commit `4c0e7ff425ecbb33e2b994b41118a71eb4e39021`.
- Added ADR-0007, architecture integration, buyer/operator runbook, threat controls, PII-preserving alternatives, requirement traceability, and APA 7th references.

## Security

- GitHub API acquisition is fixed to `https://api.github.com`, rejects redirects, caps responses at 2 MiB, rejects HTTP control characters in bearer credentials before header construction, emits sanitized errors, and excludes bearer tokens and raw logs from portable evidence.
- Invalid or unavailable evidence returns an explicit inconclusive exit path instead of being interpreted as success.
Loading
Loading