@bongos/core 1.19.339 → 1.19.341
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/.bongos-core.json +41 -26
- package/docs/adr/0188-patrol-runs-on-ci-not-the-server.md +162 -0
- package/docs/adr/README.md +1 -0
- package/docs/copy-inventory.md +153 -151
- package/docs/copy-registry.json +212 -194
- package/docs/file-map.md +1 -1
- package/docs/recipes/redteam-patrol.md +57 -6
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/cosmos.css +18 -3
- package/public-landing/projects.html +191 -51
- package/scripts/gds/control-manifest.js +10 -3
- package/scripts/gds/fitness.js +1 -0
- package/scripts/gds/redteam-patrol.js +78 -0
- package/scripts/gds/routine-schedule.js +231 -0
- package/scripts/gds/run-routine.js +14 -5
- package/src/module-api.js +5 -1
- package/tests/projects_hub.mjs +1 -1
- package/tests/projects_hub_pre_uat.mjs +85 -4
- package/tests/redteam_patrol.mjs +63 -0
- package/tests/routine_schedule.mjs +176 -0
- package/tests/run_routine.mjs +5 -2
package/docs/file-map.md
CHANGED
|
@@ -389,7 +389,7 @@ tests/
|
|
|
389
389
|
<!-- BEGIN GENERATED FILE-MAP .claude/scheduled-tasks/ (scripts/gds/gen-file-map.js — do not hand-edit; notes live in docs/file-map.notes.json) -->
|
|
390
390
|
```
|
|
391
391
|
.claude/scheduled-tasks/
|
|
392
|
-
└── redteam-weekly/SKILL.md ← weekly deterministic red-team patrol (task 1003128): full-history gitleaks scan + dependency drift review (audit delta, cooldown, young pkgs, stale overrides) + action-pin check → files security reports (advisory, ADR 0162)
|
|
392
|
+
└── redteam-weekly/SKILL.md ← weekly deterministic red-team patrol (task 1003128): full-history gitleaks scan + dependency drift review (audit delta, cooldown, young pkgs, stale overrides) + action-pin check → files security reports (advisory, ADR 0162). FIRED BY .github/workflows/redteam-patrol.yml, Mondays 06:17 UTC — `cadence: weekly` here and that cron must agree or fitness Check 25 (scripts/gds/routine-schedule.js) fails the gate (task 1003209, ADR 0188)
|
|
393
393
|
```
|
|
394
394
|
<!-- END GENERATED FILE-MAP .claude/scheduled-tasks/ -->
|
|
395
395
|
|
|
@@ -16,18 +16,69 @@ node scripts/gds/redteam-patrol.js --canary # self-test detection only
|
|
|
16
16
|
node scripts/gds/redteam-patrol.js --canary --file # prove the full pipe (files + dispute-closes)
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
## What actually fires it
|
|
20
|
+
|
|
21
|
+
**[`.github/workflows/redteam-patrol.yml`](../../.github/workflows/redteam-patrol.yml)
|
|
22
|
+
— Mondays 06:17 UTC** (task 1003209, ADR 0188). Before that lane the patrol was,
|
|
23
|
+
in the follow-up audit's words, a manual script: tracked, documented, wired into
|
|
24
|
+
the control manifest, and run zero times.
|
|
25
|
+
|
|
26
|
+
The routine itself lives at
|
|
27
|
+
[`.claude/scheduled-tasks/redteam-weekly/`](../../.claude/scheduled-tasks/redteam-weekly/SKILL.md)
|
|
28
|
+
(`mode: deterministic`, `cadence: weekly`, one step, sink `gds`) and the workflow
|
|
29
|
+
invokes it through `run-routine.js`, so the SKILL.md's `steps:` stay the single
|
|
30
|
+
source of truth for what a run does. Weekly is the cadence because the checks
|
|
31
|
+
watch drift measured in days (release-age, new advisories), not minutes.
|
|
32
|
+
|
|
33
|
+
**The cadence and the cron are checked against each other.** `cadence: weekly` in
|
|
34
|
+
the SKILL.md and `cron: '17 6 * * 1'` in the workflow must agree, or
|
|
35
|
+
`scripts/gds/routine-schedule.js` (fitness Check 25) fails the merge gate — as it
|
|
36
|
+
does if the workflow stops firing the routine, or fires one that no longer
|
|
37
|
+
exists. Change one and change the other in the same commit. The odd minute is
|
|
38
|
+
deliberate: GitHub queues scheduled workflows and top-of-hour is its worst
|
|
39
|
+
congestion window.
|
|
40
|
+
|
|
41
|
+
**Why CI and not the always-on server.** All three checks read things only the
|
|
42
|
+
*repo* has — full git history, `.github/workflows/`, an auditable lockfile. A
|
|
43
|
+
deployed instance runs a vendored core out of `node_modules/@bongos/core`, which
|
|
44
|
+
has none of them, so an in-process timer would have scanned nothing and reported
|
|
45
|
+
clean. ADR 0188 §2.1.
|
|
46
|
+
|
|
47
|
+
### Filing from CI (optional)
|
|
48
|
+
|
|
49
|
+
A CI runner has no GDS session, so by default the scheduled run **reports but
|
|
50
|
+
cannot file**: findings go to the Actions job summary and the job exits 2. To let
|
|
51
|
+
it file, set the repo secret **`GDS_PATROL_SESSION`** to a GDS CLI session JSON
|
|
52
|
+
(`{"token":…,"api_base":…}`) for a builder holding `security.report.file`; the
|
|
53
|
+
workflow writes it to the session path `instance-config` resolves and the patrol
|
|
54
|
+
files normally. This is opt-in on purpose — the patrol must not *require* a
|
|
55
|
+
long-lived token to be useful.
|
|
56
|
+
|
|
57
|
+
**Red means a finding was LOST, not that a finding exists.** Findings are
|
|
58
|
+
advisory (ADR 0162), so a run that files three of them is a success:
|
|
59
|
+
|
|
60
|
+
| the run… | exit |
|
|
61
|
+
|---|---|
|
|
62
|
+
| found nothing | 0 |
|
|
63
|
+
| was a dry run | 0 |
|
|
64
|
+
| filed its findings | 0 |
|
|
65
|
+
| has findings it cannot file | **2** |
|
|
66
|
+
|
|
67
|
+
Expect a standing `history-secrets` hit until the staging credential in commit
|
|
68
|
+
`092e473` is scrubbed from history. That is the patrol working, not the lane
|
|
69
|
+
being broken.
|
|
24
70
|
|
|
25
71
|
## Prerequisites
|
|
26
72
|
|
|
27
73
|
- **gitleaks** on PATH (`brew install gitleaks`) or `GITLEAKS_BIN=<path>`. The
|
|
28
74
|
history scan degrades LOUDLY (a printed warning, no silent skip) when absent;
|
|
29
|
-
the dependency + pin checks still run.
|
|
75
|
+
the dependency + pin checks still run. The scheduled lane installs it itself —
|
|
76
|
+
version-pinned and checksum-verified, the same binary and digest the unit gate
|
|
77
|
+
uses, rather than a mutable action tag (the tj-actions lesson).
|
|
30
78
|
- A GDS session (the normal builder token) for `--file`; dry runs need nothing.
|
|
79
|
+
`--file` preflights it, so a sessionless run prints its findings and says it
|
|
80
|
+
could not file them — it never drops into the CLI's interactive re-auth wall,
|
|
81
|
+
which in a cron log is indistinguishable from a crash.
|
|
31
82
|
- Network access to the npm registry for the dependency checks — registry
|
|
32
83
|
failures print notes and skip that item (advisory layer: fail-open, loud).
|
|
33
84
|
|
package/package-lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.341",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@bongos/core",
|
|
9
|
-
"version": "1.19.
|
|
9
|
+
"version": "1.19.341",
|
|
10
10
|
"license": "AGPL-3.0-or-later",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"express": "^4.21.2",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bongos/core",
|
|
3
|
-
"version": "1.19.
|
|
3
|
+
"version": "1.19.341",
|
|
4
4
|
"description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
|
|
5
5
|
"license": "AGPL-3.0-or-later",
|
|
6
6
|
"main": "src/platform-server.js",
|
|
@@ -201,6 +201,10 @@
|
|
|
201
201
|
|
|
202
202
|
*{box-sizing:border-box;margin:0;padding:0;}
|
|
203
203
|
[hidden]{display:none !important;}
|
|
204
|
+
/* visually-hidden: said by a screen reader, never painted. The done panel's
|
|
205
|
+
progress strip needs it (its dots carry each stage's state for the eye only),
|
|
206
|
+
and the hub's map heading and skip link ride on it. */
|
|
207
|
+
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;}
|
|
204
208
|
html{scroll-behavior:smooth;}
|
|
205
209
|
body{font-family:var(--font-body);color:var(--ink);background:var(--page-bg);min-height:100vh;-webkit-font-smoothing:antialiased;overflow-x:hidden;}
|
|
206
210
|
|
|
@@ -283,14 +287,18 @@ h1{font-family:var(--font-display);font-weight:700;font-size:clamp(24px,3.4vw,32
|
|
|
283
287
|
verification — warm when verified live, amber-dim when stale, ashen when
|
|
284
288
|
it failed its check, ghosted when torn down. Born for the dark sky; on
|
|
285
289
|
light cards the inset ring keeps it grounded. ── */
|
|
286
|
-
.orb{flex:0 0 54px;width:54px;height:54px;border-radius:50%;position:relative;overflow:visible;
|
|
290
|
+
.orb{flex:0 0 54px;width:54px;height:54px;border-radius:50%;position:relative;overflow:visible;border:none;padding:0;
|
|
287
291
|
background:radial-gradient(120% 120% at 50% 50%, var(--acc,#fb923c), color-mix(in srgb, var(--acc,#fb923c) 55%, #1b2b52) 100%);
|
|
288
292
|
box-shadow:0 0 0 1.5px rgba(255,255,255,.35) inset, 0 6px 18px rgba(20,16,40,.28), 0 0 26px var(--glow, rgba(251,146,60,.5));}
|
|
289
293
|
.orb::after{content:'';position:absolute;inset:0;border-radius:50%;pointer-events:none;
|
|
290
294
|
background:radial-gradient(38% 34% at 34% 28%, rgba(255,255,255,.9), rgba(255,255,255,0) 60%);}
|
|
291
295
|
.orb.dim{filter:saturate(.55) brightness(.92);--glow:rgba(217,119,6,.35);}
|
|
292
296
|
.orb.ashen{filter:saturate(.3) brightness(.78);--glow:rgba(220,38,38,.22);}
|
|
293
|
-
.orb.ghost{opacity:.4;box-shadow:0 0 0 1.5px rgba(255,255,255,.25) inset;filter:saturate(.2);
|
|
297
|
+
.orb.ghost{opacity:.4;box-shadow:0 0 0 1.5px rgba(255,255,255,.25) inset;filter:saturate(.2);}
|
|
298
|
+
/* only the LINKED orb is clickable: orbFor() emits a <span class="orb"> for
|
|
299
|
+
every non-navigable state, and index.html's .conItem .orb takes cursor:inherit
|
|
300
|
+
from the <a> it sits inside — so .orb.ghost's cursor reset is redundant. */
|
|
301
|
+
a.orb{cursor:pointer;}
|
|
294
302
|
|
|
295
303
|
/* ── project cards ── */
|
|
296
304
|
.projects{list-style:none;display:flex;flex-direction:column;gap:18px;}
|
|
@@ -622,6 +630,10 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
|
|
|
622
630
|
.tbl th{text-align:left;font-family:var(--font-display);font-size:11.5px;font-weight:700;
|
|
623
631
|
letter-spacing:.9px;text-transform:uppercase;color:var(--ink-faint);padding:15px 18px;
|
|
624
632
|
border-bottom:2px solid var(--line);white-space:nowrap;}
|
|
633
|
+
/* the sort control is a real button so the keyboard can reach it; it must look
|
|
634
|
+
like the header it replaced, so it inherits everything the th declares. */
|
|
635
|
+
.tbl th button{all:unset;cursor:pointer;}
|
|
636
|
+
.tbl th button:focus-visible{outline:2px solid var(--accent);outline-offset:2px;}
|
|
625
637
|
.tbl td{padding:15px 18px;border-bottom:1px solid var(--line);font-size:14px;font-weight:600;
|
|
626
638
|
color:var(--ink-soft);vertical-align:middle;}
|
|
627
639
|
.tbl tr:last-child td{border-bottom:none;}
|
|
@@ -631,7 +643,8 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
|
|
|
631
643
|
.tbl .pname{display:flex;align-items:center;gap:11px;}
|
|
632
644
|
.tbl .pdot{width:11px;height:11px;border-radius:50%;background:var(--acc);flex:0 0 auto;
|
|
633
645
|
box-shadow:0 0 0 3px color-mix(in srgb,var(--acc) 22%,transparent);}
|
|
634
|
-
.tbl .ptitle{font-family:var(--font-display);font-weight:700;font-size:15px;color:var(--ink);}
|
|
646
|
+
.tbl .ptitle{font-family:var(--font-display);font-weight:700;font-size:15px;color:var(--ink);text-decoration:none;}
|
|
647
|
+
.tbl a.ptitle:hover{text-decoration:underline;}
|
|
635
648
|
.tbl .ptag{font-size:12.5px;color:var(--ink-faint);font-weight:600;}
|
|
636
649
|
.tbl .num{font-family:var(--font-mono);font-weight:500;}
|
|
637
650
|
.tbl .tags{display:flex;gap:6px;flex-wrap:wrap;}
|
|
@@ -753,6 +766,8 @@ p.sec-p{font-size:var(--fs-lede);font-weight:500;color:var(--ink-soft);line-heig
|
|
|
753
766
|
.steps li.now .snum{border-color:var(--accent);color:var(--accent-deep);}
|
|
754
767
|
.steps .slbl{font-size:12.5px;font-weight:700;color:var(--ink-faint);}
|
|
755
768
|
.steps li.now .slbl,.steps li.done .slbl{color:var(--ink-soft);}
|
|
769
|
+
.steps li[role=button]{cursor:pointer;}
|
|
770
|
+
.steps li[role=button]:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:8px;}
|
|
756
771
|
.createSplit{display:grid;grid-template-columns:1fr 300px;gap:var(--pad-md);align-items:center;}
|
|
757
772
|
@media (max-width:840px){.createSplit{grid-template-columns:1fr;}.createSplit .bongoCell{display:none;}}
|
|
758
773
|
|