diff --git a/.failure_codes_checksum b/.failure_codes_checksum new file mode 100644 index 0000000..f3aa576 --- /dev/null +++ b/.failure_codes_checksum @@ -0,0 +1 @@ +e93a2641464504cf7bf08f42894cb7d56c8ddac19f90194eca7c50fe65199ab3 diff --git a/.github/workflows/determinism.yml b/.github/workflows/determinism.yml new file mode 100644 index 0000000..d998d3b --- /dev/null +++ b/.github/workflows/determinism.yml @@ -0,0 +1,91 @@ +name: Determinism Check + +on: + pull_request: + branches: [main] + push: + branches: [main] + +env: + LC_ALL: C + TZ: UTC + +jobs: + append-only: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + with: + fetch-depth: 0 + + - name: Check for deletions in index.html + run: | + # Get diff of index.html + DELETED=$(git diff origin/main...HEAD -- index.html | grep "^-" | grep -v "^---" | wc -l) + + if [ "$DELETED" -gt 0 ]; then + echo "FAIL: Deletions detected in index.html" + echo "This index is append-only. Deletions are not allowed." + git diff origin/main...HEAD -- index.html | grep "^-" | grep -v "^---" + exit 1 + fi + + echo "PASS: No deletions detected" + + whitespace-check: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + with: + fetch-depth: 0 + + - name: Block HTML reformatting + run: | + # Check for whitespace-only changes + CONTENT_CHANGES=$(git diff origin/main...HEAD -- index.html | grep "^[+-]" | grep -v "^[+-][+-][+-]" | grep -v "^[+-]\s*$" | wc -l) + TOTAL_CHANGES=$(git diff origin/main...HEAD -- index.html | grep "^[+-]" | grep -v "^[+-][+-][+-]" | wc -l) + + if [ "$TOTAL_CHANGES" -gt 0 ] && [ "$CONTENT_CHANGES" -eq 0 ]; then + echo "FAIL: Whitespace-only changes detected" + echo "HTML reformatting is not allowed" + exit 1 + fi + + echo "PASS: No whitespace-only changes" + + checksum-verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + + - name: Verify index checksum + run: | + ACTUAL=$(sha256sum index.html | cut -d' ' -f1) + EXPECTED=$(cat INDEX_CHECKSUM.txt | cut -d' ' -f1) + + if [ "$ACTUAL" != "$EXPECTED" ]; then + echo "FAIL: Index checksum mismatch" + echo "Expected: $EXPECTED" + echo "Actual: $ACTUAL" + exit 1 + fi + + echo "PASS: Index checksum verified" + + failure-codes-integrity: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + + - name: Verify FAILURE_CODES.json checksum + run: | + EXPECTED=$(cat .failure_codes_checksum) + ACTUAL=$(sha256sum FAILURE_CODES.json | cut -d' ' -f1) + + if [ "$EXPECTED" != "$ACTUAL" ]; then + echo "FAIL: FAILURE_CODES.json has been modified" + exit 5 + fi + echo "PASS: FAILURE_CODES.json checksum verified" diff --git a/.github/workflows/identity.yml b/.github/workflows/identity.yml new file mode 100644 index 0000000..75b7bb6 --- /dev/null +++ b/.github/workflows/identity.yml @@ -0,0 +1,59 @@ +name: Identity + +on: + workflow_call: + inputs: + identity_type: + description: 'Expected identity type (SYS or PRIM)' + required: true + type: string + identity_id: + description: 'Expected identity ID (e.g., 001, 002)' + required: true + type: string + +jobs: + verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Verify README identity + env: + EXPECTED_TYPE: ${{ inputs.identity_type }} + EXPECTED_ID: ${{ inputs.identity_id }} + run: | + set -euo pipefail + + README="README.md" + EXPECTED_IDENTITY="${EXPECTED_TYPE}-${EXPECTED_ID}" + + if [[ ! -f "$README" ]]; then + echo "FAIL: README.md not found" + exit 1 + fi + + # Extract header block + HEADER=$(sed -n '/^```$/,/^```$/p' "$README" | head -10) + + # Verify identity line + if ! echo "$HEADER" | grep -q "^${EXPECTED_IDENTITY}$"; then + echo "FAIL: Expected identity ${EXPECTED_IDENTITY} not found" + echo "Header content:" + echo "$HEADER" + exit 1 + fi + + # Verify STATUS + if ! echo "$HEADER" | grep -q "^STATUS: REGISTERED$"; then + echo "FAIL: STATUS: REGISTERED not found" + exit 1 + fi + + # Verify REGISTRY + if ! echo "$HEADER" | grep -q "^REGISTRY: https://speedkit.eu$"; then + echo "FAIL: REGISTRY: https://speedkit.eu not found" + exit 1 + fi + + echo "PASS: Identity ${EXPECTED_IDENTITY} verified" diff --git a/FAILURE_CODES.json b/FAILURE_CODES.json new file mode 100644 index 0000000..4090f56 --- /dev/null +++ b/FAILURE_CODES.json @@ -0,0 +1,5 @@ +{ + "schema": "verifrax.failure-codes.v1", + "scope": "Verifrax/.github", + "codes": {} +}