redlinegate 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +188 -0
- package/commands/redline-init.md +54 -0
- package/commands/redline-verify.md +69 -0
- package/dist/bin/redline.js +605 -0
- package/dist/bin/redline.js.map +1 -0
- package/dist/commands/exempt.js +45 -0
- package/dist/commands/exempt.js.map +1 -0
- package/dist/commands/init.js +615 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/policy.js +25 -0
- package/dist/commands/policy.js.map +1 -0
- package/dist/commands/remove.js +427 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/review.js +72 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/sync.js +42 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/commands/verify.js +478 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/config/redline-json.js +187 -0
- package/dist/config/redline-json.js.map +1 -0
- package/dist/core/errors.js +25 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/git.js +152 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/log.js +22 -0
- package/dist/core/log.js.map +1 -0
- package/dist/core/severity.js +16 -0
- package/dist/core/severity.js.map +1 -0
- package/dist/core/version.js +15 -0
- package/dist/core/version.js.map +1 -0
- package/dist/detect/scan.js +79 -0
- package/dist/detect/scan.js.map +1 -0
- package/dist/detect/stack.js +71 -0
- package/dist/detect/stack.js.map +1 -0
- package/dist/enforce/ladder.js +148 -0
- package/dist/enforce/ladder.js.map +1 -0
- package/dist/exempt/parse.js +86 -0
- package/dist/exempt/parse.js.map +1 -0
- package/dist/metrics/options.js +257 -0
- package/dist/metrics/options.js.map +1 -0
- package/dist/metrics/run.js +72 -0
- package/dist/metrics/run.js.map +1 -0
- package/dist/platforms/azure/client.js +53 -0
- package/dist/platforms/azure/client.js.map +1 -0
- package/dist/platforms/azure/index.js +69 -0
- package/dist/platforms/azure/index.js.map +1 -0
- package/dist/platforms/azure/install.js +917 -0
- package/dist/platforms/azure/install.js.map +1 -0
- package/dist/platforms/azure/policy-types.js +70 -0
- package/dist/platforms/azure/policy-types.js.map +1 -0
- package/dist/platforms/azure/verify.js +309 -0
- package/dist/platforms/azure/verify.js.map +1 -0
- package/dist/platforms/detect.js +40 -0
- package/dist/platforms/detect.js.map +1 -0
- package/dist/platforms/github/client.js +49 -0
- package/dist/platforms/github/client.js.map +1 -0
- package/dist/platforms/github/index.js +54 -0
- package/dist/platforms/github/index.js.map +1 -0
- package/dist/platforms/github/install.js +558 -0
- package/dist/platforms/github/install.js.map +1 -0
- package/dist/platforms/github/push.js +102 -0
- package/dist/platforms/github/push.js.map +1 -0
- package/dist/platforms/github/remote.js +36 -0
- package/dist/platforms/github/remote.js.map +1 -0
- package/dist/platforms/github/verify.js +366 -0
- package/dist/platforms/github/verify.js.map +1 -0
- package/dist/platforms/http.js +58 -0
- package/dist/platforms/http.js.map +1 -0
- package/dist/platforms/pull-request-templates.js +157 -0
- package/dist/platforms/pull-request-templates.js.map +1 -0
- package/dist/platforms/remote.js +21 -0
- package/dist/platforms/remote.js.map +1 -0
- package/dist/platforms/resolve.js +69 -0
- package/dist/platforms/resolve.js.map +1 -0
- package/dist/platforms/shape.js +19 -0
- package/dist/platforms/shape.js.map +1 -0
- package/dist/platforms/types.js +24 -0
- package/dist/platforms/types.js.map +1 -0
- package/dist/policy/checks.js +91 -0
- package/dist/policy/checks.js.map +1 -0
- package/dist/policy/diff.js +50 -0
- package/dist/policy/diff.js.map +1 -0
- package/dist/registry/discover.js +74 -0
- package/dist/registry/discover.js.map +1 -0
- package/dist/registry/serialize.js +41 -0
- package/dist/registry/serialize.js.map +1 -0
- package/dist/registry/types.js +2 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/remove/host.js +294 -0
- package/dist/remove/host.js.map +1 -0
- package/dist/render/commands.js +139 -0
- package/dist/render/commands.js.map +1 -0
- package/dist/render/manifest.js +82 -0
- package/dist/render/manifest.js.map +1 -0
- package/dist/render/markers.js +166 -0
- package/dist/render/markers.js.map +1 -0
- package/dist/render/profile.js +23 -0
- package/dist/render/profile.js.map +1 -0
- package/dist/render/standards.js +169 -0
- package/dist/render/standards.js.map +1 -0
- package/dist/render/vendors.js +199 -0
- package/dist/render/vendors.js.map +1 -0
- package/dist/review/engines/api.js +95 -0
- package/dist/review/engines/api.js.map +1 -0
- package/dist/review/engines/embedded.js +20 -0
- package/dist/review/engines/embedded.js.map +1 -0
- package/dist/review/engines/types.js +2 -0
- package/dist/review/engines/types.js.map +1 -0
- package/dist/review/glob.js +29 -0
- package/dist/review/glob.js.map +1 -0
- package/dist/review/prompt.js +45 -0
- package/dist/review/prompt.js.map +1 -0
- package/dist/review/rules.js +25 -0
- package/dist/review/rules.js.map +1 -0
- package/dist/review/schema.js +84 -0
- package/dist/review/schema.js.map +1 -0
- package/dist/review/scope.js +27 -0
- package/dist/review/scope.js.map +1 -0
- package/dist/sarif/map.js +58 -0
- package/dist/sarif/map.js.map +1 -0
- package/dist/sarif/parse.js +88 -0
- package/dist/sarif/parse.js.map +1 -0
- package/dist/sarif/types.js +2 -0
- package/dist/sarif/types.js.map +1 -0
- package/dist/sync/host.js +21 -0
- package/dist/sync/host.js.map +1 -0
- package/dist/sync/plan.js +47 -0
- package/dist/sync/plan.js.map +1 -0
- package/dist/sync/render.js +57 -0
- package/dist/sync/render.js.map +1 -0
- package/dist/sync/run.js +118 -0
- package/dist/sync/run.js.map +1 -0
- package/dist/verify/host.js +52 -0
- package/dist/verify/host.js.map +1 -0
- package/dist/verify/remote.js +146 -0
- package/dist/verify/remote.js.map +1 -0
- package/package.json +52 -0
- package/platforms/azure/gate-template.yml +105 -0
- package/rulesets/redline-org-ruleset.json +46 -0
- package/rulesets/redline-ruleset.json +49 -0
- package/scripts/assign-rule-ids.mjs +129 -0
- package/scripts/build-baseline.mjs +124 -0
- package/scripts/build-correlation.mjs +74 -0
- package/scripts/build-dashboard.mjs +584 -0
- package/scripts/build-digest.mjs +164 -0
- package/scripts/build-inbox.mjs +133 -0
- package/scripts/build-registry.mjs +42 -0
- package/scripts/build-roi.mjs +181 -0
- package/scripts/check-pins.mjs +88 -0
- package/scripts/collect-telemetry.mjs +300 -0
- package/scripts/lib/__tests__/baseline.test.mjs +132 -0
- package/scripts/lib/__tests__/correlate.test.mjs +131 -0
- package/scripts/lib/__tests__/dora.test.mjs +110 -0
- package/scripts/lib/__tests__/exemptions.test.mjs +85 -0
- package/scripts/lib/__tests__/metrics-scanner.test.mjs +65 -0
- package/scripts/lib/__tests__/sarif.test.mjs +125 -0
- package/scripts/lib/__tests__/spend.test.mjs +64 -0
- package/scripts/lib/baseline.mjs +156 -0
- package/scripts/lib/correlate.mjs +125 -0
- package/scripts/lib/dora.mjs +133 -0
- package/scripts/lib/exemptions.mjs +79 -0
- package/scripts/lib/metrics.mjs +172 -0
- package/scripts/lib/rules.mjs +107 -0
- package/scripts/lib/sarif.mjs +108 -0
- package/scripts/lib/spend.mjs +69 -0
- package/scripts/measure-context.mjs +101 -0
- package/scripts/render-self.mjs +18 -0
- package/scripts/score-seeds.mjs +294 -0
- package/scripts/validate.mjs +394 -0
- package/standards/core.md +124 -0
- package/standards/manifest.json +214 -0
- package/standards/stacks/csharp.md +29 -0
- package/standards/stacks/go.md +30 -0
- package/standards/stacks/java.md +30 -0
- package/standards/stacks/javascript.md +42 -0
- package/standards/stacks/kotlin.md +27 -0
- package/standards/stacks/microservices.md +37 -0
- package/standards/stacks/nodejs.md +34 -0
- package/standards/stacks/python.md +29 -0
- package/standards/stacks/react-native.md +29 -0
- package/standards/stacks/react.md +46 -0
- package/standards/stacks/swift.md +26 -0
- package/standards/stacks/terraform.md +27 -0
- package/templates/CODEOWNERS +29 -0
- package/templates/azure/pull_request_template.md +72 -0
- package/templates/github/pull_request_template.md +72 -0
- package/templates/redline.yml +35 -0
- package/templates/repo-context.md +64 -0
- package/workflows/dashboard.yml +119 -0
- package/workflows/inbox.yml +97 -0
- package/workflows/redline-collect.yml +61 -0
- package/workflows/redline-gate.yml +301 -0
- package/workflows/redline-sync.yml +79 -0
- package/workflows/seed-canary.yml +231 -0
- package/workflows/verify-onboarding.yml +115 -0
- package/workflows/weekly-digest.yml +78 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Lives in the Redline source repo. Re-verifies every onboarded repo on a schedule and
|
|
2
|
+
# opens one tracking issue when any of them has drifted — a ruleset edited by hand, a
|
|
3
|
+
# renamed caller job, push protection switched off, artifacts left stale by an ignored
|
|
4
|
+
# sync pull request.
|
|
5
|
+
#
|
|
6
|
+
# Drift is silent by nature: a repository whose gate stopped publishing looks exactly
|
|
7
|
+
# like one whose gate is green and quiet. This loop is what makes the difference visible
|
|
8
|
+
# without anyone going to look.
|
|
9
|
+
#
|
|
10
|
+
# Targets come from registry.json — the same derived register sync uses. A check that
|
|
11
|
+
# genuinely needs a working tree reports `??` rather than passing, so a repository is
|
|
12
|
+
# never reported healthy on the strength of a check that did not run.
|
|
13
|
+
name: Redline Verify Onboarding
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
schedule:
|
|
17
|
+
- cron: '0 6 * * 2'
|
|
18
|
+
workflow_dispatch:
|
|
19
|
+
inputs:
|
|
20
|
+
only:
|
|
21
|
+
description: Verify a single repo, as owner/name
|
|
22
|
+
type: string
|
|
23
|
+
required: false
|
|
24
|
+
|
|
25
|
+
permissions:
|
|
26
|
+
contents: read
|
|
27
|
+
issues: write
|
|
28
|
+
|
|
29
|
+
concurrency:
|
|
30
|
+
group: redline-verify-onboarding
|
|
31
|
+
cancel-in-progress: false
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
verify:
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
timeout-minutes: 45
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v4
|
|
39
|
+
- uses: actions/setup-node@v4
|
|
40
|
+
with:
|
|
41
|
+
node-version: 22
|
|
42
|
+
|
|
43
|
+
- name: Install
|
|
44
|
+
run: npm ci
|
|
45
|
+
|
|
46
|
+
- name: Build CLI
|
|
47
|
+
run: npm run build
|
|
48
|
+
|
|
49
|
+
- name: Verify every registered repository
|
|
50
|
+
id: verify
|
|
51
|
+
env:
|
|
52
|
+
GH_TOKEN: ${{ secrets.REDLINE_ORG_READ_TOKEN }}
|
|
53
|
+
ONLY: ${{ inputs.only }}
|
|
54
|
+
run: |
|
|
55
|
+
set -uo pipefail
|
|
56
|
+
if [ ! -f registry.json ]; then
|
|
57
|
+
echo "::error::registry.json is missing — the register has not been derived yet."
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
if [ -n "$ONLY" ]; then
|
|
62
|
+
repos="$ONLY"
|
|
63
|
+
else
|
|
64
|
+
# String concatenation rather than a template literal: `${...}` inside
|
|
65
|
+
# single quotes is ambiguous to a reader and to shellcheck, which
|
|
66
|
+
# cannot know the braces are JavaScript's. Avoiding the construct
|
|
67
|
+
# beats suppressing the warning about it.
|
|
68
|
+
repos=$(node -e 'const r=require("./registry.json");for(const e of r.entries)if(e.host==="github")console.log(e.org+"/"+e.repo)')
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
: > drift.txt
|
|
72
|
+
# `set -e` is deliberately NOT on for this loop: a drifted repository
|
|
73
|
+
# exits non-zero by design, and aborting on the first one would leave
|
|
74
|
+
# the rest of the estate unverified every week.
|
|
75
|
+
while read -r repo; do
|
|
76
|
+
[ -z "$repo" ] && continue
|
|
77
|
+
echo "--- $repo"
|
|
78
|
+
if ! node dist/bin/redline.js verify --repo "$repo" 2>&1 | tee /tmp/out.txt; then
|
|
79
|
+
{
|
|
80
|
+
echo "### $repo"
|
|
81
|
+
echo '```'
|
|
82
|
+
grep -E '^(FAIL| \?\?)' /tmp/out.txt || cat /tmp/out.txt
|
|
83
|
+
echo '```'
|
|
84
|
+
} >> drift.txt
|
|
85
|
+
fi
|
|
86
|
+
done <<< "$repos"
|
|
87
|
+
|
|
88
|
+
if [ -s drift.txt ]; then
|
|
89
|
+
echo "drift=true" >> "$GITHUB_OUTPUT"
|
|
90
|
+
else
|
|
91
|
+
echo "drift=false" >> "$GITHUB_OUTPUT"
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
- name: Open or update the drift issue
|
|
95
|
+
if: steps.verify.outputs.drift == 'true'
|
|
96
|
+
env:
|
|
97
|
+
GH_TOKEN: ${{ github.token }}
|
|
98
|
+
TITLE: 'Redline: onboarded repositories have drifted'
|
|
99
|
+
run: |
|
|
100
|
+
set -euo pipefail
|
|
101
|
+
# One issue, updated in place. A new issue per run turns a standing
|
|
102
|
+
# problem into a backlog nobody reads.
|
|
103
|
+
body=$(cat drift.txt)
|
|
104
|
+
existing=$(gh issue list --state open --search "$TITLE in:title" --json number --jq '.[0].number // empty')
|
|
105
|
+
if [ -n "$existing" ]; then
|
|
106
|
+
gh issue comment "$existing" --body "$body"
|
|
107
|
+
else
|
|
108
|
+
gh issue create --title "$TITLE" --body "$body"
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
- name: Summarise
|
|
112
|
+
if: always()
|
|
113
|
+
run: |
|
|
114
|
+
if [ -s drift.txt ]; then cat drift.txt >> "$GITHUB_STEP_SUMMARY";
|
|
115
|
+
else echo "No drift detected." >> "$GITHUB_STEP_SUMMARY"; fi
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Lives in the redline-metrics repo. Monday-morning stakeholder digest.
|
|
2
|
+
#
|
|
3
|
+
# TEAMS_WEBHOOK_URL must point at a Power Automate "When a Teams webhook request is
|
|
4
|
+
# received" flow. The old Office 365 connector webhooks (the `{"text": "..."}` shape)
|
|
5
|
+
# were retired by Microsoft and silently stop delivering.
|
|
6
|
+
name: Redline Weekly Digest
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
schedule:
|
|
10
|
+
- cron: '0 7 * * 1'
|
|
11
|
+
workflow_dispatch:
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
digest:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
timeout-minutes: 15
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: actions/setup-node@v4
|
|
23
|
+
with:
|
|
24
|
+
node-version: 22
|
|
25
|
+
|
|
26
|
+
- name: Count open and stale PRs
|
|
27
|
+
id: prs
|
|
28
|
+
env:
|
|
29
|
+
GH_TOKEN: ${{ secrets.REDLINE_ORG_READ_TOKEN }}
|
|
30
|
+
ORG: ${{ github.repository_owner }}
|
|
31
|
+
run: |
|
|
32
|
+
set -euo pipefail
|
|
33
|
+
cutoff=$(date -u -d '7 days ago' +%Y-%m-%d)
|
|
34
|
+
|
|
35
|
+
# gh search caps at 1000 results; --json + jq length would silently truncate.
|
|
36
|
+
# total_count from the REST search endpoint is exact.
|
|
37
|
+
count() {
|
|
38
|
+
gh api -X GET search/issues -f q="$1" -f per_page=1 --jq '.total_count'
|
|
39
|
+
}
|
|
40
|
+
open_prs=$(count "org:$ORG is:pr is:open draft:false")
|
|
41
|
+
stale_prs=$(count "org:$ORG is:pr is:open draft:false updated:<$cutoff")
|
|
42
|
+
|
|
43
|
+
echo "open=$open_prs" >> "$GITHUB_OUTPUT"
|
|
44
|
+
echo "stale=$stale_prs" >> "$GITHUB_OUTPUT"
|
|
45
|
+
|
|
46
|
+
- name: Build Adaptive Card
|
|
47
|
+
run: |
|
|
48
|
+
npx --yes "redlinegate@0.0.1" metrics digest \
|
|
49
|
+
--org "${{ github.repository_owner }}" \
|
|
50
|
+
--days 7 \
|
|
51
|
+
--open-prs "${{ steps.prs.outputs.open }}" \
|
|
52
|
+
--stale-prs "${{ steps.prs.outputs.stale }}" \
|
|
53
|
+
--seed-scores data/seed-scores.jsonl \
|
|
54
|
+
--dashboard-url "${{ vars.REDLINE_DASHBOARD_URL }}" \
|
|
55
|
+
--out digest.json
|
|
56
|
+
|
|
57
|
+
- name: Post to Teams
|
|
58
|
+
env:
|
|
59
|
+
WEBHOOK: ${{ secrets.TEAMS_WEBHOOK_URL }}
|
|
60
|
+
run: |
|
|
61
|
+
set -euo pipefail
|
|
62
|
+
if [[ -z "${WEBHOOK:-}" ]]; then
|
|
63
|
+
echo "::error::TEAMS_WEBHOOK_URL is not set — digest built but not delivered."
|
|
64
|
+
exit 1
|
|
65
|
+
fi
|
|
66
|
+
curl -sS --fail-with-body -X POST \
|
|
67
|
+
-H 'Content-Type: application/json' \
|
|
68
|
+
--data @digest.json "$WEBHOOK"
|
|
69
|
+
|
|
70
|
+
- name: Attach digest to the run
|
|
71
|
+
if: always()
|
|
72
|
+
run: |
|
|
73
|
+
{
|
|
74
|
+
echo '### Digest payload'
|
|
75
|
+
echo '```json'
|
|
76
|
+
cat digest.json 2>/dev/null || echo '{}'
|
|
77
|
+
echo '```'
|
|
78
|
+
} >> "$GITHUB_STEP_SUMMARY"
|