Skip to content

Fix TypeScript import errors: remove underscore prefixes from type im… #85

Fix TypeScript import errors: remove underscore prefixes from type im…

Fix TypeScript import errors: remove underscore prefixes from type im… #85

name: code-to-gate Release Readiness
on:
push:
branches: [main]
workflow_dispatch:
inputs:
release_tag:
description: 'Release tag for evidence'
required: false
default: ''
policy_file:
description: 'Policy file path'
required: false
default: '.github/ctg-policy.yaml'
schedule:
# Weekly acceptance test: Sunday at 00:00 UTC
- cron: '0 0 * * 0'
permissions:
contents: read
security-events: write
actions: read
env:
RELEASE_TAG: ${{ github.event.inputs.release_tag || github.sha }}
jobs:
macos-compatibility:
runs-on: macos-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Run smoke tests
run: npm run test:smoke
- name: Verify CLI on macOS
run: |
node ./dist/cli.js --help
node ./dist/cli.js scan fixtures/demo-ci-imports --out .qh-macos-smoke
analyze:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Run full analysis
id: analyze
run: |
set +e
node ./dist/cli.js analyze . \
--policy ${{ github.event.inputs.policy_file || '.github/ctg-policy.yaml' }} \
--emit all \
--out .qh \
--format json
ANALYZE_EXIT=$?
set -e
if [ "$ANALYZE_EXIT" -ne 0 ] && [ ! -f .qh/findings.json ]; then
echo "::error::Analysis failed before producing findings artifacts"
exit "$ANALYZE_EXIT"
fi
if [ "$ANALYZE_EXIT" -ne 0 ]; then
echo "::notice::Analysis produced findings and exited with code $ANALYZE_EXIT; continuing to readiness evaluation"
fi
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- name: Evaluate release readiness
id: readiness
run: |
set +e
node ./dist/cli.js readiness . \
--policy ${{ github.event.inputs.policy_file || '.github/ctg-policy.yaml' }} \
--from .qh \
--out .qh
READINESS_EXIT=$?
set -e
if [ "$READINESS_EXIT" -ne 0 ] && [ ! -f .qh/release-readiness.json ]; then
echo "::error::Readiness evaluation failed before producing release-readiness.json"
exit "$READINESS_EXIT"
fi
if [ "$READINESS_EXIT" -ne 0 ]; then
echo "::notice::Readiness gate returned code $READINESS_EXIT; preserving artifacts for the final gate step"
fi
if [ -f .qh/release-readiness.json ]; then
STATUS=$(jq -r '.status' .qh/release-readiness.json)
echo "status=$STATUS" >> $GITHUB_OUTPUT
SUMMARY=$(jq -r '.summary // "No summary available"' .qh/release-readiness.json)
echo "summary=$SUMMARY" >> $GITHUB_OUTPUT
CRITICAL=$(jq '.counts.critical // .findings_summary.critical // 0' .qh/release-readiness.json)
HIGH=$(jq '.counts.high // .findings_summary.high // 0' .qh/release-readiness.json)
MEDIUM=$(jq '.counts.medium // .findings_summary.medium // 0' .qh/release-readiness.json)
echo "critical_count=$CRITICAL" >> $GITHUB_OUTPUT
echo "high_count=$HIGH" >> $GITHUB_OUTPUT
echo "medium_count=$MEDIUM" >> $GITHUB_OUTPUT
else
echo "status=unknown" >> $GITHUB_OUTPUT
echo "summary=Release readiness file not found" >> $GITHUB_OUTPUT
fi
- name: Export SARIF
run: node ./dist/cli.js export sarif --from .qh --out .qh/results.sarif
- name: Upload SARIF to code scanning
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: .qh/results.sarif
category: code-to-gate-release
- name: Generate release evidence
run: |
node ./dist/cli.js export workflow-evidence --from .qh --out .qh/workflow-evidence.json
# Create release evidence summary
cat > .qh/release-evidence.md << 'EOF'
# Release Evidence
**Release Tag**: ${{ env.RELEASE_TAG }}
**Commit**: ${{ github.sha }}
**Workflow Run**: ${{ github.run_id }}
**Timestamp**: ${{ github.event.head_commit.timestamp || github.event.repository.pushed_at }}
**Status**: ${{ steps.readiness.outputs.status }}
## Summary
${{ steps.readiness.outputs.summary }}
## Findings Count
- Critical: ${{ steps.readiness.outputs.critical_count }}
- High: ${{ steps.readiness.outputs.high_count }}
- Medium: ${{ steps.readiness.outputs.medium_count }}
## Artifacts
- [Release Readiness](./release-readiness.json)
- [Findings](./findings.json)
- [Risk Register](./risk-register.yaml)
- [Test Seeds](./test-seeds.json)
- [SARIF Report](./results.sarif)
- [Workflow Evidence](./workflow-evidence.json)
EOF
- name: Upload release evidence artifacts
uses: actions/upload-artifact@v7
with:
name: ctg-release-evidence-${{ github.sha }}
path: |
.qh/release-readiness.json
.qh/findings.json
.qh/risk-register.yaml
.qh/test-seeds.json
.qh/analysis-report.md
.qh/results.sarif
.qh/workflow-evidence.json
.qh/release-evidence.md
.qh/audit.json
retention-days: 90
- name: Block release if not ready
if: steps.readiness.outputs.status == 'blocked_input' || steps.readiness.outputs.status == 'needs_review'
run: |
echo "::error::Release blocked - readiness status: ${{ steps.readiness.outputs.status }}"
echo "Summary: ${{ steps.readiness.outputs.summary }}"
echo ""
echo "Product gate checklist reference: RUNBOOK.md section 6.9"
echo "P0 requirements:"
echo " - P0-01: CI/release procedure connection (this workflow)"
echo " - P0-02: Policy evaluator unified (verify: audit.json exit matches readiness)"
echo " - P0-03: 3 real repos verified (run: scripts/real-repo-test.ps1)"
echo " - P0-04: FP rate <= 15% (check: findings should have evidence-backed)"
exit 1
- name: Report success
if: steps.readiness.outputs.status == 'passed' || steps.readiness.outputs.status == 'passed_with_risk'
run: |
echo "::notice::Release readiness passed with status: ${{ steps.readiness.outputs.status }}"
echo "Summary: ${{ steps.readiness.outputs.summary }}"
# P0-03: Periodic real repo acceptance (weekly)
acceptance:
runs-on: ubuntu-latest
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Run fixture acceptance
run: |
pwsh -File ./scripts/fixture-acceptance.ps1 -OutDir .qh/acceptance/fixtures
- name: Upload acceptance evidence
uses: actions/upload-artifact@v7
with:
name: ctg-acceptance-evidence-${{ github.sha }}
path: .qh/acceptance/
retention-days: 90