Files
git.stella-ops.org/.gitea/workflows/unknowns-budget-gate.yml
Workflow config file is invalid. Please check your config file: yaml: line 139: did not find expected comment or line break
StellaOps Bot 5146204f1b feat: add security sink detection patterns for JavaScript/TypeScript
- Introduced `sink-detect.js` with various security sink detection patterns categorized by type (e.g., command injection, SQL injection, file operations).
- Implemented functions to build a lookup map for fast sink detection and to match sink calls against known patterns.
- Added `package-lock.json` for dependency management.
2025-12-22 23:21:21 +02:00

200 lines
6.2 KiB
YAML

# -----------------------------------------------------------------------------
# unknowns-budget-gate.yml
# Sprint: SPRINT_5100_0004_0001_unknowns_budget_ci_gates
# Task: T2 - CI Budget Gate Workflow
# Description: Enforces unknowns budgets on PRs and pushes
# -----------------------------------------------------------------------------
name: Unknowns Budget Gate
on:
pull_request:
paths:
- 'src/**'
- 'Dockerfile*'
- '*.lock'
- 'etc/policy.unknowns.yaml'
push:
branches: [main]
paths:
- 'src/**'
- 'Dockerfile*'
- '*.lock'
env:
DOTNET_NOLOGO: 1
DOTNET_CLI_TELEMETRY_OPTOUT: 1
TZ: UTC
STELLAOPS_BUDGET_CONFIG: ./etc/policy.unknowns.yaml
jobs:
scan-and-check-budget:
runs-on: ubuntu-22.04
permissions:
contents: read
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.100'
include-prerelease: true
- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: |
~/.nuget/packages
local-nugets/packages
key: budget-gate-nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj') }}
- name: Restore and Build CLI
run: |
dotnet restore src/Cli/StellaOps.Cli/StellaOps.Cli.csproj --configfile nuget.config
dotnet build src/Cli/StellaOps.Cli/StellaOps.Cli.csproj -c Release --no-restore
- name: Determine environment
id: env
run: |
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
echo "environment=prod" >> $GITHUB_OUTPUT
echo "enforce=true" >> $GITHUB_OUTPUT
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo "environment=stage" >> $GITHUB_OUTPUT
echo "enforce=false" >> $GITHUB_OUTPUT
else
echo "environment=dev" >> $GITHUB_OUTPUT
echo "enforce=false" >> $GITHUB_OUTPUT
fi
- name: Create sample verdict for testing
id: scan
run: |
mkdir -p out
# In a real scenario, this would be from stella scan
# For now, create a minimal verdict file
cat > out/verdict.json << 'EOF'
{
"unknowns": []
}
EOF
echo "verdict_path=out/verdict.json" >> $GITHUB_OUTPUT
- name: Check unknowns budget
id: budget
continue-on-error: true
run: |
set +e
dotnet run --project src/Cli/StellaOps.Cli/StellaOps.Cli.csproj -- \
unknowns budget check \
--verdict ${{ steps.scan.outputs.verdict_path }} \
--environment ${{ steps.env.outputs.environment }} \
--output json \
--fail-on-exceed > out/budget-result.json
EXIT_CODE=$?
echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT
if [ -f out/budget-result.json ]; then
# Compact JSON for output
RESULT=$(cat out/budget-result.json | jq -c '.')
echo "result=$RESULT" >> $GITHUB_OUTPUT
fi
exit $EXIT_CODE
- name: Upload budget report
uses: actions/upload-artifact@v4
if: always()
with:
name: budget-report-${{ github.run_id }}
path: out/budget-result.json
retention-days: 30
- name: Post PR comment
if: github.event_name == 'pull_request' && always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
let result = { isWithinBudget: true, totalUnknowns: 0 };
try {
const content = fs.readFileSync('out/budget-result.json', 'utf8');
result = JSON.parse(content);
} catch (e) {
console.log('Could not read budget result:', e.message);
}
const status = result.isWithinBudget ? ':white_check_mark:' : ':x:';
const env = '${{ steps.env.outputs.environment }}';
let body = `## ${status} Unknowns Budget Check
| Metric | Value |
|--------|-------|
| Environment | ${env} |
| Total Unknowns | ${result.totalUnknowns || 0} |
| Budget Limit | ${result.totalLimit || 'Unlimited'} |
| Status | ${result.isWithinBudget ? 'PASS' : 'FAIL'} |
`;
if (result.violations && result.violations.length > 0) {
body += `
### Violations
`;
for (const v of result.violations) {
body += `- **${v.reasonCode}**: ${v.count}/${v.limit}\n`;
}
}
if (result.message) {
body += `\n> ${result.message}\n`;
}
body += `\n---\n_Generated by StellaOps Unknowns Budget Gate_`;
// Find existing comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(c =>
c.body.includes('Unknowns Budget Check') &&
c.user.type === 'Bot'
);
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: body
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: body
});
}
- name: Fail if budget exceeded (prod)
if: steps.env.outputs.environment == 'prod' && steps.budget.outputs.exit_code == '2'
run: |
echo "::error::Production unknowns budget exceeded!"
exit 1
- name: Warn if budget exceeded (non-prod)
if: steps.env.outputs.environment != 'prod' && steps.budget.outputs.exit_code == '2'
run: |
echo "::warning::Unknowns budget exceeded for ${{ steps.env.outputs.environment }}"