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.
Files changed (198) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +188 -0
  3. package/commands/redline-init.md +54 -0
  4. package/commands/redline-verify.md +69 -0
  5. package/dist/bin/redline.js +605 -0
  6. package/dist/bin/redline.js.map +1 -0
  7. package/dist/commands/exempt.js +45 -0
  8. package/dist/commands/exempt.js.map +1 -0
  9. package/dist/commands/init.js +615 -0
  10. package/dist/commands/init.js.map +1 -0
  11. package/dist/commands/policy.js +25 -0
  12. package/dist/commands/policy.js.map +1 -0
  13. package/dist/commands/remove.js +427 -0
  14. package/dist/commands/remove.js.map +1 -0
  15. package/dist/commands/review.js +72 -0
  16. package/dist/commands/review.js.map +1 -0
  17. package/dist/commands/sync.js +42 -0
  18. package/dist/commands/sync.js.map +1 -0
  19. package/dist/commands/verify.js +478 -0
  20. package/dist/commands/verify.js.map +1 -0
  21. package/dist/config/redline-json.js +187 -0
  22. package/dist/config/redline-json.js.map +1 -0
  23. package/dist/core/errors.js +25 -0
  24. package/dist/core/errors.js.map +1 -0
  25. package/dist/core/git.js +152 -0
  26. package/dist/core/git.js.map +1 -0
  27. package/dist/core/log.js +22 -0
  28. package/dist/core/log.js.map +1 -0
  29. package/dist/core/severity.js +16 -0
  30. package/dist/core/severity.js.map +1 -0
  31. package/dist/core/version.js +15 -0
  32. package/dist/core/version.js.map +1 -0
  33. package/dist/detect/scan.js +79 -0
  34. package/dist/detect/scan.js.map +1 -0
  35. package/dist/detect/stack.js +71 -0
  36. package/dist/detect/stack.js.map +1 -0
  37. package/dist/enforce/ladder.js +148 -0
  38. package/dist/enforce/ladder.js.map +1 -0
  39. package/dist/exempt/parse.js +86 -0
  40. package/dist/exempt/parse.js.map +1 -0
  41. package/dist/metrics/options.js +257 -0
  42. package/dist/metrics/options.js.map +1 -0
  43. package/dist/metrics/run.js +72 -0
  44. package/dist/metrics/run.js.map +1 -0
  45. package/dist/platforms/azure/client.js +53 -0
  46. package/dist/platforms/azure/client.js.map +1 -0
  47. package/dist/platforms/azure/index.js +69 -0
  48. package/dist/platforms/azure/index.js.map +1 -0
  49. package/dist/platforms/azure/install.js +917 -0
  50. package/dist/platforms/azure/install.js.map +1 -0
  51. package/dist/platforms/azure/policy-types.js +70 -0
  52. package/dist/platforms/azure/policy-types.js.map +1 -0
  53. package/dist/platforms/azure/verify.js +309 -0
  54. package/dist/platforms/azure/verify.js.map +1 -0
  55. package/dist/platforms/detect.js +40 -0
  56. package/dist/platforms/detect.js.map +1 -0
  57. package/dist/platforms/github/client.js +49 -0
  58. package/dist/platforms/github/client.js.map +1 -0
  59. package/dist/platforms/github/index.js +54 -0
  60. package/dist/platforms/github/index.js.map +1 -0
  61. package/dist/platforms/github/install.js +558 -0
  62. package/dist/platforms/github/install.js.map +1 -0
  63. package/dist/platforms/github/push.js +102 -0
  64. package/dist/platforms/github/push.js.map +1 -0
  65. package/dist/platforms/github/remote.js +36 -0
  66. package/dist/platforms/github/remote.js.map +1 -0
  67. package/dist/platforms/github/verify.js +366 -0
  68. package/dist/platforms/github/verify.js.map +1 -0
  69. package/dist/platforms/http.js +58 -0
  70. package/dist/platforms/http.js.map +1 -0
  71. package/dist/platforms/pull-request-templates.js +157 -0
  72. package/dist/platforms/pull-request-templates.js.map +1 -0
  73. package/dist/platforms/remote.js +21 -0
  74. package/dist/platforms/remote.js.map +1 -0
  75. package/dist/platforms/resolve.js +69 -0
  76. package/dist/platforms/resolve.js.map +1 -0
  77. package/dist/platforms/shape.js +19 -0
  78. package/dist/platforms/shape.js.map +1 -0
  79. package/dist/platforms/types.js +24 -0
  80. package/dist/platforms/types.js.map +1 -0
  81. package/dist/policy/checks.js +91 -0
  82. package/dist/policy/checks.js.map +1 -0
  83. package/dist/policy/diff.js +50 -0
  84. package/dist/policy/diff.js.map +1 -0
  85. package/dist/registry/discover.js +74 -0
  86. package/dist/registry/discover.js.map +1 -0
  87. package/dist/registry/serialize.js +41 -0
  88. package/dist/registry/serialize.js.map +1 -0
  89. package/dist/registry/types.js +2 -0
  90. package/dist/registry/types.js.map +1 -0
  91. package/dist/remove/host.js +294 -0
  92. package/dist/remove/host.js.map +1 -0
  93. package/dist/render/commands.js +139 -0
  94. package/dist/render/commands.js.map +1 -0
  95. package/dist/render/manifest.js +82 -0
  96. package/dist/render/manifest.js.map +1 -0
  97. package/dist/render/markers.js +166 -0
  98. package/dist/render/markers.js.map +1 -0
  99. package/dist/render/profile.js +23 -0
  100. package/dist/render/profile.js.map +1 -0
  101. package/dist/render/standards.js +169 -0
  102. package/dist/render/standards.js.map +1 -0
  103. package/dist/render/vendors.js +199 -0
  104. package/dist/render/vendors.js.map +1 -0
  105. package/dist/review/engines/api.js +95 -0
  106. package/dist/review/engines/api.js.map +1 -0
  107. package/dist/review/engines/embedded.js +20 -0
  108. package/dist/review/engines/embedded.js.map +1 -0
  109. package/dist/review/engines/types.js +2 -0
  110. package/dist/review/engines/types.js.map +1 -0
  111. package/dist/review/glob.js +29 -0
  112. package/dist/review/glob.js.map +1 -0
  113. package/dist/review/prompt.js +45 -0
  114. package/dist/review/prompt.js.map +1 -0
  115. package/dist/review/rules.js +25 -0
  116. package/dist/review/rules.js.map +1 -0
  117. package/dist/review/schema.js +84 -0
  118. package/dist/review/schema.js.map +1 -0
  119. package/dist/review/scope.js +27 -0
  120. package/dist/review/scope.js.map +1 -0
  121. package/dist/sarif/map.js +58 -0
  122. package/dist/sarif/map.js.map +1 -0
  123. package/dist/sarif/parse.js +88 -0
  124. package/dist/sarif/parse.js.map +1 -0
  125. package/dist/sarif/types.js +2 -0
  126. package/dist/sarif/types.js.map +1 -0
  127. package/dist/sync/host.js +21 -0
  128. package/dist/sync/host.js.map +1 -0
  129. package/dist/sync/plan.js +47 -0
  130. package/dist/sync/plan.js.map +1 -0
  131. package/dist/sync/render.js +57 -0
  132. package/dist/sync/render.js.map +1 -0
  133. package/dist/sync/run.js +118 -0
  134. package/dist/sync/run.js.map +1 -0
  135. package/dist/verify/host.js +52 -0
  136. package/dist/verify/host.js.map +1 -0
  137. package/dist/verify/remote.js +146 -0
  138. package/dist/verify/remote.js.map +1 -0
  139. package/package.json +52 -0
  140. package/platforms/azure/gate-template.yml +105 -0
  141. package/rulesets/redline-org-ruleset.json +46 -0
  142. package/rulesets/redline-ruleset.json +49 -0
  143. package/scripts/assign-rule-ids.mjs +129 -0
  144. package/scripts/build-baseline.mjs +124 -0
  145. package/scripts/build-correlation.mjs +74 -0
  146. package/scripts/build-dashboard.mjs +584 -0
  147. package/scripts/build-digest.mjs +164 -0
  148. package/scripts/build-inbox.mjs +133 -0
  149. package/scripts/build-registry.mjs +42 -0
  150. package/scripts/build-roi.mjs +181 -0
  151. package/scripts/check-pins.mjs +88 -0
  152. package/scripts/collect-telemetry.mjs +300 -0
  153. package/scripts/lib/__tests__/baseline.test.mjs +132 -0
  154. package/scripts/lib/__tests__/correlate.test.mjs +131 -0
  155. package/scripts/lib/__tests__/dora.test.mjs +110 -0
  156. package/scripts/lib/__tests__/exemptions.test.mjs +85 -0
  157. package/scripts/lib/__tests__/metrics-scanner.test.mjs +65 -0
  158. package/scripts/lib/__tests__/sarif.test.mjs +125 -0
  159. package/scripts/lib/__tests__/spend.test.mjs +64 -0
  160. package/scripts/lib/baseline.mjs +156 -0
  161. package/scripts/lib/correlate.mjs +125 -0
  162. package/scripts/lib/dora.mjs +133 -0
  163. package/scripts/lib/exemptions.mjs +79 -0
  164. package/scripts/lib/metrics.mjs +172 -0
  165. package/scripts/lib/rules.mjs +107 -0
  166. package/scripts/lib/sarif.mjs +108 -0
  167. package/scripts/lib/spend.mjs +69 -0
  168. package/scripts/measure-context.mjs +101 -0
  169. package/scripts/render-self.mjs +18 -0
  170. package/scripts/score-seeds.mjs +294 -0
  171. package/scripts/validate.mjs +394 -0
  172. package/standards/core.md +124 -0
  173. package/standards/manifest.json +214 -0
  174. package/standards/stacks/csharp.md +29 -0
  175. package/standards/stacks/go.md +30 -0
  176. package/standards/stacks/java.md +30 -0
  177. package/standards/stacks/javascript.md +42 -0
  178. package/standards/stacks/kotlin.md +27 -0
  179. package/standards/stacks/microservices.md +37 -0
  180. package/standards/stacks/nodejs.md +34 -0
  181. package/standards/stacks/python.md +29 -0
  182. package/standards/stacks/react-native.md +29 -0
  183. package/standards/stacks/react.md +46 -0
  184. package/standards/stacks/swift.md +26 -0
  185. package/standards/stacks/terraform.md +27 -0
  186. package/templates/CODEOWNERS +29 -0
  187. package/templates/azure/pull_request_template.md +72 -0
  188. package/templates/github/pull_request_template.md +72 -0
  189. package/templates/redline.yml +35 -0
  190. package/templates/repo-context.md +64 -0
  191. package/workflows/dashboard.yml +119 -0
  192. package/workflows/inbox.yml +97 -0
  193. package/workflows/redline-collect.yml +61 -0
  194. package/workflows/redline-gate.yml +301 -0
  195. package/workflows/redline-sync.yml +79 -0
  196. package/workflows/seed-canary.yml +231 -0
  197. package/workflows/verify-onboarding.yml +115 -0
  198. package/workflows/weekly-digest.yml +78 -0
@@ -0,0 +1,29 @@
1
+ # Reference shape only. `redline init` builds equivalent content in code and never reads
2
+ # this file — it writes .github/CODEOWNERS only on a repository that has none yet, and
3
+ # leaves an existing one untouched.
4
+ #
5
+ # The branch ruleset sets require_code_owner_review: true. Without a CODEOWNERS file that
6
+ # rule is a silent no-op, so the platform team must own at minimum the enforcement surface
7
+ # below — otherwise any contributor can weaken their own gate in a self-approved PR.
8
+ #
9
+ # Replace <org>/<team> placeholders before installing by hand.
10
+
11
+ # Default owner for everything not matched below.
12
+ * @<org>/<owning-team>
13
+
14
+ # --- Enforcement surface: platform team must approve any change here -------------------
15
+ # Editing the caller workflow, the ruleset, or the review standards changes what this
16
+ # repo is allowed to merge. These are the paths an attacker or a rushed engineer would
17
+ # touch to make the gate stop failing.
18
+ /.github/workflows/ @<org>/platform-engineering
19
+ /.github/CODEOWNERS @<org>/platform-engineering
20
+ /.github/copilot-instructions.md @<org>/platform-engineering
21
+ /.github/instructions/ @<org>/platform-engineering
22
+ /AGENTS.md @<org>/platform-engineering
23
+ /CLAUDE.md @<org>/platform-engineering
24
+
25
+ # --- Security-sensitive paths ---------------------------------------------------------
26
+ /infra/ @<org>/platform-engineering
27
+ /terraform/ @<org>/platform-engineering
28
+ Dockerfile @<org>/platform-engineering
29
+ /.github/dependabot.yml @<org>/platform-engineering
@@ -0,0 +1,72 @@
1
+ # Summary
2
+
3
+ <!-- What and why, 2-3 sentences. Link the ticket. -->
4
+
5
+ Ticket:
6
+
7
+ ## Change type
8
+
9
+ <!-- Tick the one that applies. This section is NOT gated — pick one and move on. -->
10
+
11
+ - [ ] Feature
12
+ - [ ] Bugfix
13
+ - [ ] Refactor (approved beforehand)
14
+ - [ ] Chore/config
15
+
16
+ <!-- REDLINE:BEGIN — generated by Redline. Do not edit inside this block. -->
17
+
18
+ ## Launch readiness
19
+
20
+ <!--
21
+ GATED SECTION. `redline-gate` fails while any box here is unticked.
22
+ If an item genuinely does not apply, delete the line and say why in the Summary.
23
+ Do not delete the heading — the gate fails if the section is missing.
24
+ -->
25
+
26
+ - [ ] No secrets, keys, or customer data in code, logs, or fixtures
27
+ - [ ] Input validated at boundaries touched by this change
28
+ - [ ] Typecheck and lint pass with no new errors
29
+ - [ ] Tested on: <!-- iOS / Android / web / staging -->
30
+ - [ ] Error states handled (network failure, empty, loading)
31
+ - [ ] Rollback is safe (no destructive migration, no breaking contract change)
32
+ - [ ] No unrelated changes in the diff
33
+
34
+ ## Architecture decision
35
+
36
+ <!-- If this PR makes a non-obvious technical choice, add an ADR and link it. Otherwise delete this section. -->
37
+
38
+ ADR: `docs/adr/NNNN-*.md`
39
+
40
+ ## Redline exemption
41
+
42
+ <!--
43
+ Only fill this in if a process check above is failing and you are asking to merge anyway.
44
+ Delete the whole section otherwise. A label alone no longer exempts anything: the gate
45
+ reads THIS block, and an exemption with no reason and no end date is an opt-out, not an
46
+ exemption.
47
+
48
+ - reason: what is being accepted and why, in a sentence a reader in three months
49
+ can act on. "Needed for release" is not one.
50
+ - until: YYYY-MM-DD, at most 90 days out. Longer than that is a standards change,
51
+ not an exemption — raise it in the Redline source repo.
52
+ - scope: which checks it covers (checklist, adr). Omit to cover both.
53
+
54
+ This can never exempt dependency review or the secret scan. Those do not soft-fail.
55
+ -->
56
+
57
+ - reason:
58
+ - until:
59
+ - scope:
60
+
61
+ <!-- REDLINE:END -->
62
+
63
+ ## Automated review
64
+
65
+ - [ ] Review comments addressed, or dismissed in-thread with a reason
66
+
67
+ <!--
68
+ Gate stuck on a process check you cannot satisfy? Add the `redline-exempt` label to
69
+ this pull request and leave a comment explaining why. That downgrades the checklist
70
+ and ADR checks to warnings. It does NOT bypass dependency review or the secret scan —
71
+ those never soft-fail.
72
+ -->
@@ -0,0 +1,72 @@
1
+ # Summary
2
+
3
+ <!-- What and why, 2-3 sentences. Link the ticket. -->
4
+
5
+ Ticket:
6
+
7
+ ## Change type
8
+
9
+ <!-- Tick the one that applies. This section is NOT gated — pick one and move on. -->
10
+
11
+ - [ ] Feature
12
+ - [ ] Bugfix
13
+ - [ ] Refactor (approved beforehand)
14
+ - [ ] Chore/config
15
+
16
+ <!-- REDLINE:BEGIN — generated by Redline. Do not edit inside this block. -->
17
+
18
+ ## Launch readiness
19
+
20
+ <!--
21
+ GATED SECTION. `redline-gate` fails while any box here is unticked.
22
+ If an item genuinely does not apply, delete the line and say why in the Summary.
23
+ Do not delete the heading — the gate fails if the section is missing.
24
+ -->
25
+
26
+ - [ ] No secrets, keys, or customer data in code, logs, or fixtures
27
+ - [ ] Input validated at boundaries touched by this change
28
+ - [ ] Typecheck and lint pass with no new errors
29
+ - [ ] Tested on: <!-- iOS / Android / web / staging -->
30
+ - [ ] Error states handled (network failure, empty, loading)
31
+ - [ ] Rollback is safe (no destructive migration, no breaking contract change)
32
+ - [ ] No unrelated changes in the diff
33
+
34
+ ## Architecture decision
35
+
36
+ <!-- If this PR makes a non-obvious technical choice, add an ADR and link it. Otherwise delete this section. -->
37
+
38
+ ADR: `docs/adr/NNNN-*.md`
39
+
40
+ ## Redline exemption
41
+
42
+ <!--
43
+ Only fill this in if a process check above is failing and you are asking to merge anyway.
44
+ Delete the whole section otherwise. A label alone no longer exempts anything: the gate
45
+ reads THIS block, and an exemption with no reason and no end date is an opt-out, not an
46
+ exemption.
47
+
48
+ - reason: what is being accepted and why, in a sentence a reader in three months
49
+ can act on. "Needed for release" is not one.
50
+ - until: YYYY-MM-DD, at most 90 days out. Longer than that is a standards change,
51
+ not an exemption — raise it in the Redline source repo.
52
+ - scope: which checks it covers (checklist, adr). Omit to cover both.
53
+
54
+ This can never exempt dependency review or the secret scan. Those do not soft-fail.
55
+ -->
56
+
57
+ - reason:
58
+ - until:
59
+ - scope:
60
+
61
+ <!-- REDLINE:END -->
62
+
63
+ ## Automated review
64
+
65
+ - [ ] Review comments addressed, or dismissed in-thread with a reason
66
+
67
+ <!--
68
+ Gate stuck on a process check you cannot satisfy? Apply the `redline-exempt` label AND
69
+ fill in the `## Redline exemption` section above. The label says a check was waived; the
70
+ block says who accepted what, why, and until when — and the gate reads the block.
71
+ It does NOT bypass dependency review or the secret scan — those never soft-fail.
72
+ -->
@@ -0,0 +1,35 @@
1
+ # Managed by Redline; regenerate with `redline init` rather than editing here.
2
+ # Redline caller. Installed into every onboarded repo as .github/workflows/redline.yml
3
+ # by `redline init`. Kept in sync by workflows/redline-sync.yml once `redline sync`
4
+ # ships in Phase 3 — see CHANGELOG.md.
5
+ #
6
+ # DO NOT RENAME THE JOB. The branch ruleset requires the check "redline-gate / gate",
7
+ # which is derived from this job id plus the aggregate job id in the reusable workflow.
8
+ # Renaming it makes the required check unreportable and blocks every PR in this repo.
9
+ #
10
+ # Replace <org> with the organisation that hosts the `.github` repo.
11
+ name: Redline
12
+
13
+ on:
14
+ pull_request:
15
+ types: [opened, synchronize, reopened, edited, labeled, unlabeled, ready_for_review]
16
+
17
+ permissions:
18
+ contents: read
19
+ pull-requests: write
20
+
21
+ concurrency:
22
+ group: redline-${{ github.event.pull_request.number }}
23
+ cancel-in-progress: true
24
+
25
+ jobs:
26
+ redline-gate:
27
+ uses: <org>/.github/.github/workflows/redline-gate.yml@main
28
+ with:
29
+ adr-diff-threshold: 300
30
+ fail-on-dependency-severity: high
31
+ soft-fail-labels: redline-exempt,redline-sync
32
+ # Written by `redline init --rung`. observe and warn report without blocking;
33
+ # block-blocker and block-high stop a merge. The security floor — dependency
34
+ # review and the secret scan — is not on this ladder and blocks at every rung.
35
+ rung: observe
@@ -0,0 +1,64 @@
1
+ # Project context
2
+
3
+ <!--
4
+ TEMPLATE. Copy the content of this file to the TOP of the target repo's AGENTS.md,
5
+ above the `<!-- REDLINE:BEGIN -->` marker, and fill the bracketed sections.
6
+
7
+ Everything above the marker is owned by your team and is never overwritten by
8
+ Redline sync. Everything inside the marker block is generated — do not edit it.
9
+
10
+ Why this file matters: review quality is bounded by context. A reviewer that does
11
+ not know FlashList is the standard cannot flag FlatList.
12
+ -->
13
+
14
+ ## What this repo is
15
+
16
+ [One paragraph: product name, what it does, who uses it, which market. e.g. "Customer
17
+ self-care app for <market>, React Native (Expo) plus shared web components."]
18
+
19
+ ## Architecture
20
+
21
+ - **App shell:** [Expo SDK NN / Next.js NN / Spring Boot N.N / NestJS NN]
22
+ - **State:** server state via [TanStack Query]; client UI state via [Zustand]. No Redux.
23
+ - **Navigation:** [expo-router / react-navigation native-stack]
24
+ - **Styling:** [StyleSheet.create / Nativewind / styled-components]
25
+ - **API layer:** [BFF at `src/api/`; types generated from OpenAPI into `src/api/types/`]
26
+ - **Persistence:** [Postgres via Prisma / JPA + Flyway]
27
+ - **Messaging:** [Kafka topics owned: ...]
28
+ - **Lists:** [FlashList is the standard; FlatList only for legacy screens.]
29
+ - **Images:** [expo-image everywhere.]
30
+
31
+ ## Directory map
32
+
33
+ ```
34
+ src/
35
+ api/ # BFF client + generated types — do not hand-edit generated files
36
+ components/ # shared UI, design-system components
37
+ screens/ # one folder per screen
38
+ hooks/ # shared hooks
39
+ utils/ # pure functions only, no framework imports
40
+ ```
41
+
42
+ ## Team conventions
43
+
44
+ - [TypeScript strict mode; `noUncheckedIndexedAccess` on.]
45
+ - Error handling only at boundaries (API calls, storage, native modules, user input).
46
+ - Comments only for non-obvious WHY, never WHAT.
47
+ - Minimal diffs; no drive-by refactors in feature PRs.
48
+ - Architecture decisions recorded as ADRs in `docs/adr/NNNN-title.md`.
49
+
50
+ ## Deliberate deviations from Redline
51
+
52
+ <!--
53
+ List rules this repo knowingly does not follow, with the reason. Reviewers should not
54
+ re-raise these. If the list grows past a few entries, the standard is wrong — raise it
55
+ in the Redline source repo instead of accumulating exceptions here.
56
+ -->
57
+
58
+ - [e.g. "`any` permitted in `src/legacy/**` until MIG-4412 completes."]
59
+
60
+ ## Review context
61
+
62
+ - PRs may be authored by AI coding agents or contractors — review with the same rigour.
63
+ - Merge requires one human approval plus green required checks. Automated review is
64
+ advisory input to the human reviewer; it never approves.
@@ -0,0 +1,119 @@
1
+ # Lives in the redline-metrics repo. Rebuilds the Redline dashboard from collected
2
+ # telemetry and publishes it to GitHub Pages.
3
+ #
4
+ # SECURITY: the page lists repo names, rule ids and finding counts. Set the Pages site to
5
+ # private or internal visibility BEFORE enabling this. The build refuses to run until
6
+ # PAGES_VISIBILITY_ACKNOWLEDGED is set as a repository variable.
7
+ name: Redline Dashboard
8
+
9
+ on:
10
+ schedule:
11
+ - cron: '30 5 * * *'
12
+ workflow_dispatch:
13
+ workflow_run:
14
+ # Rebuild as soon as new telemetry lands, so the page is never a day behind the data.
15
+ workflows: [Redline Collect, Redline Seed Canary]
16
+ types: [completed]
17
+
18
+ permissions:
19
+ contents: read
20
+ pages: write
21
+ id-token: write
22
+
23
+ concurrency:
24
+ group: dashboard
25
+ cancel-in-progress: true
26
+
27
+ jobs:
28
+ build:
29
+ runs-on: ubuntu-latest
30
+ timeout-minutes: 15
31
+ steps:
32
+ - name: Confirm Pages visibility was reviewed
33
+ env:
34
+ ACK: ${{ vars.PAGES_VISIBILITY_ACKNOWLEDGED }}
35
+ run: |
36
+ if [[ "${ACK:-}" != "private" && "${ACK:-}" != "internal" ]]; then
37
+ echo "::error::Set the repository variable PAGES_VISIBILITY_ACKNOWLEDGED to 'private' or 'internal' after confirming the Pages site is not public. This page exposes org-wide delivery detail."
38
+ exit 1
39
+ fi
40
+
41
+ - uses: actions/checkout@v4
42
+ - uses: actions/setup-node@v4
43
+ with:
44
+ node-version: 22
45
+
46
+ - name: Count onboarded repos
47
+ id: coverage
48
+ env:
49
+ GH_TOKEN: ${{ secrets.REDLINE_ORG_READ_TOKEN }}
50
+ SOURCE: ${{ vars.REDLINE_SOURCE || format('{0}/redline', github.repository_owner) }}
51
+ run: |
52
+ set -euo pipefail
53
+ # registry.json is the derived register of onboarded repositories, refreshed
54
+ # nightly by the source repo's Redline Registry workflow. Coverage is
55
+ # instrumented-vs-onboarded, so partial coverage cannot read as health. A
56
+ # failed read omits the figure rather than reporting zero — absent is honest,
57
+ # zero is a lie that looks like a finding.
58
+ # Written to a file rather than counted here: the dashboard reads the whole
59
+ # register for the enforcement ladder, not just its length, and a count
60
+ # alone cannot say how much of the estate is actually enforcing.
61
+ if gh api "repos/$SOURCE/contents/registry.json" --jq '.content' 2>/dev/null | base64 -d > registry.json; then
62
+ echo "found=true" >> "$GITHUB_OUTPUT"
63
+ else
64
+ rm -f registry.json
65
+ echo "found=false" >> "$GITHUB_OUTPUT"
66
+ echo "::warning::Could not read registry.json from $SOURCE — coverage and the ladder will be omitted."
67
+ fi
68
+
69
+ # No checkout of the Redline source, and no copy of its scripts in this
70
+ # repository. The command ships in the package; this repo owns its data and
71
+ # nothing else.
72
+ - name: Build dashboard
73
+ env:
74
+ STANDARDS_VERSION: ${{ vars.STANDARDS_VERSION }}
75
+ run: |
76
+ npx --yes "redlinegate@0.0.1" metrics dashboard \
77
+ --org "${{ github.repository_owner }}" \
78
+ --data data \
79
+ --days 90 \
80
+ --out dist \
81
+ --registry registry.json
82
+
83
+ - uses: actions/upload-pages-artifact@v3
84
+ with:
85
+ path: dist
86
+
87
+ deploy:
88
+ needs: build
89
+ runs-on: ubuntu-latest
90
+ environment:
91
+ name: github-pages
92
+ url: ${{ steps.deployment.outputs.page_url }}
93
+ steps:
94
+ - id: deployment
95
+ uses: actions/deploy-pages@v4
96
+
97
+ alert:
98
+ needs: [build, deploy]
99
+ if: failure()
100
+ runs-on: ubuntu-latest
101
+ permissions:
102
+ contents: read
103
+ issues: write
104
+ steps:
105
+ - name: Open or update a failure issue
106
+ env:
107
+ GH_TOKEN: ${{ github.token }}
108
+ REPO: ${{ github.repository }}
109
+ RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
110
+ run: |
111
+ set -euo pipefail
112
+ title="Redline dashboard build is failing"
113
+ existing=$(gh issue list --repo "$REPO" --state open --search "$title in:title" --json number --jq '.[0].number // ""')
114
+ if [[ -n "$existing" ]]; then
115
+ gh issue comment "$existing" --repo "$REPO" --body "Still failing: $RUN"
116
+ else
117
+ gh issue create --repo "$REPO" --title "$title" \
118
+ --body "The dashboard build failed, so the published page is now stale. Run: $RUN"
119
+ fi
@@ -0,0 +1,97 @@
1
+ # Lives in the Redline source repo. Rebuilds the org-wide PR inbox on a schedule and
2
+ # publishes it to GitHub Pages.
3
+ #
4
+ # SECURITY: the page lists PR titles, authors and repo names. Set the Pages site to
5
+ # private or internal visibility (Settings > Pages > Visibility) BEFORE enabling this.
6
+ # On a public Pages site this publishes internal delivery detail to the internet. The
7
+ # build refuses to run until PAGES_VISIBILITY_ACKNOWLEDGED is set as a repo variable.
8
+ name: Redline Inbox
9
+
10
+ on:
11
+ schedule:
12
+ - cron: '*/30 6-19 * * 1-5'
13
+ workflow_dispatch:
14
+
15
+ permissions:
16
+ contents: read
17
+ pages: write
18
+ id-token: write
19
+
20
+ concurrency:
21
+ group: inbox
22
+ cancel-in-progress: true
23
+
24
+ jobs:
25
+ build:
26
+ runs-on: ubuntu-latest
27
+ timeout-minutes: 15
28
+ steps:
29
+ - name: Confirm Pages visibility was reviewed
30
+ env:
31
+ ACK: ${{ vars.PAGES_VISIBILITY_ACKNOWLEDGED }}
32
+ run: |
33
+ if [[ "${ACK:-}" != "private" && "${ACK:-}" != "internal" ]]; then
34
+ echo "::error::Set the repository variable PAGES_VISIBILITY_ACKNOWLEDGED to 'private' or 'internal' after confirming the Pages site is not public. This page exposes org-wide PR titles and authors."
35
+ exit 1
36
+ fi
37
+
38
+ - uses: actions/checkout@v4
39
+ - uses: actions/setup-node@v4
40
+ with:
41
+ node-version: 22
42
+
43
+ - name: Install and build
44
+ run: |
45
+ npm ci
46
+ npm run build
47
+
48
+ # This one runs in the source repo, so it uses the build it is about to
49
+ # ship rather than the last published package: a broken inbox here is a
50
+ # broken command, and finding that out from the release is too late.
51
+ - name: Build inbox
52
+ env:
53
+ GH_TOKEN: ${{ secrets.REDLINE_ORG_READ_TOKEN }}
54
+ run: |
55
+ node dist/bin/redline.js metrics inbox \
56
+ --org "${{ github.repository_owner }}" \
57
+ --out dist
58
+
59
+ - uses: actions/upload-pages-artifact@v3
60
+ with:
61
+ path: dist
62
+
63
+ deploy:
64
+ needs: build
65
+ runs-on: ubuntu-latest
66
+ environment:
67
+ name: github-pages
68
+ url: ${{ steps.deployment.outputs.page_url }}
69
+ steps:
70
+ - id: deployment
71
+ uses: actions/deploy-pages@v4
72
+
73
+ # A silently stale inbox is worse than no inbox: people trust a page that stopped
74
+ # updating three weeks ago. Surface the failure where someone will see it.
75
+ alert:
76
+ needs: [build, deploy]
77
+ if: failure()
78
+ runs-on: ubuntu-latest
79
+ permissions:
80
+ contents: read
81
+ issues: write
82
+ steps:
83
+ - name: Open or update a failure issue
84
+ env:
85
+ GH_TOKEN: ${{ github.token }}
86
+ REPO: ${{ github.repository }}
87
+ RUN: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
88
+ run: |
89
+ set -euo pipefail
90
+ title="Redline inbox build is failing"
91
+ existing=$(gh issue list --repo "$REPO" --state open --search "$title in:title" --json number --jq '.[0].number // ""')
92
+ if [[ -n "$existing" ]]; then
93
+ gh issue comment "$existing" --repo "$REPO" --body "Still failing: $RUN"
94
+ else
95
+ gh issue create --repo "$REPO" --title "$title" \
96
+ --body "The scheduled inbox build failed. The published page is now stale. Run: $RUN"
97
+ fi
@@ -0,0 +1,61 @@
1
+ # Lives in the redline-metrics repo. Pulls review outcomes for merged PRs across the org
2
+ # and commits them as monthly JSONL.
3
+ #
4
+ # Replaces the old per-repo telemetry workflow: no Redline secret is stored in any
5
+ # product repo, so onboarding a repo grants Redline no write access to anything.
6
+ name: Redline Collect
7
+
8
+ on:
9
+ schedule:
10
+ - cron: '0 5 * * *'
11
+ workflow_dispatch:
12
+ inputs:
13
+ days:
14
+ description: Look-back window in days
15
+ type: string
16
+ default: '8'
17
+
18
+ permissions:
19
+ contents: write
20
+
21
+ concurrency:
22
+ group: redline-collect
23
+ cancel-in-progress: false
24
+
25
+ jobs:
26
+ collect:
27
+ runs-on: ubuntu-latest
28
+ timeout-minutes: 30
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: actions/setup-node@v4
32
+ with:
33
+ node-version: 22
34
+
35
+ - name: Collect telemetry
36
+ env:
37
+ # Read-only: repo metadata + pull requests across the org. No write scope.
38
+ # The token travels as an environment variable rather than a flag: a
39
+ # command line is visible in the process table.
40
+ GH_TOKEN: ${{ secrets.REDLINE_ORG_READ_TOKEN }}
41
+ run: |
42
+ npx --yes "redlinegate@0.0.1" metrics collect \
43
+ --org "${{ github.repository_owner }}" \
44
+ --days "${{ inputs.days || '8' }}" \
45
+ --out data
46
+
47
+ - name: Commit
48
+ run: |
49
+ set -euo pipefail
50
+ if git diff --quiet -- data; then
51
+ echo "no telemetry changes" >> "$GITHUB_STEP_SUMMARY"
52
+ exit 0
53
+ fi
54
+ git config user.name "redline-bot"
55
+ git config user.email "redline-bot@users.noreply.github.com"
56
+ git add data
57
+ git commit -m "data: telemetry through $(date -u +%Y-%m-%d)"
58
+ # Another run (or a digest commit) may have landed since checkout.
59
+ git pull --rebase origin "${GITHUB_REF_NAME}"
60
+ git push origin "HEAD:${GITHUB_REF_NAME}"
61
+ git diff --stat HEAD~1 -- data >> "$GITHUB_STEP_SUMMARY"