@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.
@@ -0,0 +1,176 @@
1
+ // tests/routine_schedule.mjs — a declared cadence must have something that fires
2
+ // it (task 1003209, goal 1000079; ADR 0188, follow-up audit §7).
3
+ //
4
+ // The check exists because goal 1000076's patrol was "wired" by every predicate
5
+ // the repo had and still ran zero times. So these tests are written against the
6
+ // ways that state can come BACK, not merely against the happy path: the strongest
7
+ // one is the cron silently drifting off the declared cadence, which no
8
+ // existence/substring predicate can ever catch.
9
+ //
10
+ // Hermetic — the evaluator is pure and driven with fixtures; the two live-tree
11
+ // tests at the bottom assert the real repo is in the state this task shipped.
12
+ import assert from 'node:assert/strict';
13
+ import { test } from 'node:test';
14
+ import { createRequire } from 'node:module';
15
+ import fs from 'node:fs';
16
+ import path from 'node:path';
17
+ import { fileURLToPath } from 'node:url';
18
+
19
+ const require = createRequire(import.meta.url);
20
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
21
+ const rs = require(path.join(ROOT, 'scripts', 'gds', 'routine-schedule.js'));
22
+ const { parseRoutineFrontmatter } = require(path.join(ROOT, 'scripts', 'gds', 'run-routine.js'));
23
+
24
+ const WEEKLY_WF = {
25
+ file: 'redteam-patrol.yml',
26
+ text: [
27
+ 'on:',
28
+ ' schedule:',
29
+ " - cron: '17 6 * * 1'",
30
+ ' workflow_dispatch:',
31
+ 'jobs:',
32
+ ' patrol:',
33
+ ' steps:',
34
+ ' - run: node scripts/gds/run-routine.js redteam-weekly',
35
+ ].join('\n'),
36
+ };
37
+ const routines = (withCadence, withoutCadence = []) => ({ withCadence, withoutCadence });
38
+ const WEEKLY = [{ name: 'redteam-weekly', cadence: 'weekly', steps: [] }];
39
+
40
+ // ---------------------------------------------------------------- cron parsing
41
+
42
+ test('cronCadence classifies the four periods a routine may declare', () => {
43
+ assert.equal(rs.cronCadence('17 6 * * 1'), 'weekly');
44
+ assert.equal(rs.cronCadence('17 6 * * *'), 'daily');
45
+ assert.equal(rs.cronCadence('17 6 3 * *'), 'monthly');
46
+ assert.equal(rs.cronCadence('17 * * * *'), 'hourly');
47
+ });
48
+
49
+ test('cronCadence refuses what its vocabulary cannot describe, rather than guessing', () => {
50
+ // Unclassifiable must mean "never matches a declared cadence" — the safe
51
+ // direction. A clever cron that silently counted as `weekly` would reopen
52
+ // exactly the drift this check exists to catch.
53
+ for (const expr of ['*/5 * * * *', '0 6 * * 1-5', '0 6 * * 1,4', '0 0 1 1 *', '17 6 * *', '', 'nonsense']) {
54
+ assert.equal(rs.cronCadence(expr), null, `${expr} should not classify`);
55
+ }
56
+ // A day-of-month AND day-of-week together is an OR in cron — neither period.
57
+ assert.equal(rs.cronCadence('17 6 3 * 1'), null);
58
+ });
59
+
60
+ test('workflowCrons reads every cron a workflow declares, quoted or bare, ignoring trailing comments', () => {
61
+ const y = [" schedule:", " - cron: '17 6 * * 1'", ' - cron: "0 3 * * *"', ' - cron: 5 * * * * # bare + comment'].join('\n');
62
+ assert.deepEqual(rs.workflowCrons(y), ['17 6 * * 1', '0 3 * * *', '5 * * * *']);
63
+ assert.deepEqual(rs.workflowCrons(''), []);
64
+ });
65
+
66
+ // ------------------------------------------------------------- what counts as
67
+ // an invocation
68
+
69
+ test('invokesRoutine accepts the dispatcher form and a verbatim step command', () => {
70
+ assert.equal(rs.invokesRoutine('run: node scripts/gds/run-routine.js redteam-weekly', 'redteam-weekly'), true);
71
+ assert.equal(rs.invokesRoutine('run: node scripts/gds/run-routine.js --dry-run redteam-weekly', 'redteam-weekly'), true);
72
+ assert.equal(
73
+ rs.invokesRoutine('run: node scripts/gds/redteam-patrol.js --file', 'redteam-weekly',
74
+ [{ command: 'node scripts/gds/redteam-patrol.js --file' }]),
75
+ true);
76
+ });
77
+
78
+ test('invokesRoutine does not accept a prefix match for a different routine', () => {
79
+ // `redteam-weekly-v2` must not satisfy `redteam-weekly` — that would let a
80
+ // renamed routine keep the old one's green.
81
+ assert.equal(rs.invokesRoutine('node scripts/gds/run-routine.js redteam-weekly-v2', 'redteam-weekly'), false);
82
+ });
83
+
84
+ // ------------------------------------------------------------------ the check
85
+
86
+ test('a routine fired weekly by a weekly cron passes', () => {
87
+ const { violations } = rs.evaluate(routines(WEEKLY), [WEEKLY_WF]);
88
+ assert.deepEqual(violations, []);
89
+ });
90
+
91
+ test('THE regression this check exists for: the cron drifts off the declared cadence', () => {
92
+ // Every existence/substring predicate in the repo stays green here — the file
93
+ // exists, the workflow still names the routine, the manifest needle still hits.
94
+ // Only a relational check sees it.
95
+ const drifted = { ...WEEKLY_WF, text: WEEKLY_WF.text.replace('17 6 * * 1', '17 6 3 * *') };
96
+ const { violations } = rs.evaluate(routines(WEEKLY), [drifted]);
97
+ assert.equal(violations.length, 1);
98
+ assert.match(violations[0], /declares cadence: weekly but no scheduler fires it at that period/);
99
+ assert.match(violations[0], /→ monthly/);
100
+ });
101
+
102
+ test('dispatch-only is not scheduled — the exact state the audit called "decorative"', () => {
103
+ const manual = { ...WEEKLY_WF, text: WEEKLY_WF.text.replace(/ schedule:\n.*\n/, '') };
104
+ const { violations } = rs.evaluate(routines(WEEKLY), [manual]);
105
+ assert.equal(violations.length, 1);
106
+ assert.match(violations[0], /carries no 'on: schedule:' cron \(manual dispatch only\)/);
107
+ });
108
+
109
+ test('a cadence with no scheduler at all is a violation where CI exists', () => {
110
+ const { violations } = rs.evaluate(routines(WEEKLY), []);
111
+ assert.equal(violations.length, 1);
112
+ assert.match(violations[0], /NOTHING fires it/);
113
+ });
114
+
115
+ test('rename rot is caught from the other side: a scheduler dispatching a routine that is gone', () => {
116
+ const { violations } = rs.evaluate(routines([], [{ name: 'something-else' }]), [WEEKLY_WF]);
117
+ assert.equal(violations.length, 1, violations.join(' | '));
118
+ assert.match(violations[0], /dispatches routine 'redteam-weekly', which has no/);
119
+ });
120
+
121
+ test('a workflow naming its own invocation twice reports one problem, not two', () => {
122
+ const twice = { ...WEEKLY_WF, text: `# see run-routine.js redteam-weekly below\n${WEEKLY_WF.text}` };
123
+ const { violations } = rs.evaluate(routines([], []), [twice]);
124
+ assert.equal(violations.length, 1);
125
+ });
126
+
127
+ test('an unknown cadence word is refused rather than silently unenforceable', () => {
128
+ const { violations } = rs.evaluate(routines([{ name: 'r', cadence: 'fortnightly', steps: [] }]), []);
129
+ assert.equal(violations.length, 1);
130
+ assert.match(violations[0], /unknown cadence "fortnightly"/);
131
+ });
132
+
133
+ test('an instance checkout (no .github/workflows) warns instead of red-building', () => {
134
+ // Routines are materialized into every instance; .github/workflows is the core
135
+ // repo's and does not travel. Hard-failing there would red every instance for
136
+ // owning a scheduler the core cannot see.
137
+ const { violations, warnings } = rs.evaluate(routines(WEEKLY), null);
138
+ assert.deepEqual(violations, []);
139
+ assert.equal(warnings.length, 1);
140
+ assert.match(warnings[0], /NOTHING fires it/);
141
+ });
142
+
143
+ test('a routine with no cadence is a warning — it can only ever be run by hand', () => {
144
+ const { violations, warnings } = rs.evaluate(routines([], [{ name: 'manual-thing' }]), []);
145
+ assert.deepEqual(violations, []);
146
+ assert.match(warnings.join(' '), /declares no cadence/);
147
+ });
148
+
149
+ // --------------------------------------------------------------- the live tree
150
+
151
+ test('the frontmatter parser reads cadence: alongside mode: and steps:', () => {
152
+ const md = ['---', 'mode: deterministic', 'cadence: weekly', 'description: d', 'steps:',
153
+ ' - command: node x.js', ' sink: gds', '---', '# body'].join('\n');
154
+ const fm = parseRoutineFrontmatter(md);
155
+ assert.equal(fm.cadence, 'weekly');
156
+ assert.equal(fm.mode, 'deterministic');
157
+ assert.equal(fm.steps.length, 1);
158
+ // Absent cadence must be null, not undefined — evaluate() branches on truthiness.
159
+ assert.equal(parseRoutineFrontmatter('---\nmode: deterministic\n---\n').cadence, null);
160
+ });
161
+
162
+ test('LIVE: redteam-weekly declares a cadence and this repo actually fires it', () => {
163
+ const r = rs.checkRoutineCadencesScheduled();
164
+ assert.equal(r.hardFail, false, r.violations.join(' | '));
165
+ assert.ok(rs.readRoutines().withCadence.some((x) => x.name === 'redteam-weekly'),
166
+ 'redteam-weekly must declare a cadence — without it nothing can schedule it');
167
+ });
168
+
169
+ test('LIVE: the patrol workflow installs gitleaks, which the history scan cannot run without', () => {
170
+ // The follow-up audit listed the missing binary as its own gap; a scheduled
171
+ // patrol without it degrades to "history scan SKIPPED" every week forever.
172
+ const wf = fs.readFileSync(path.join(ROOT, '.github', 'workflows', 'redteam-patrol.yml'), 'utf8');
173
+ assert.match(wf, /GITLEAKS_BIN=/, 'the patrol must be handed a gitleaks binary');
174
+ assert.match(wf, /sha256sum -c -/, 'the binary must be checksum-verified (the tj-actions lesson)');
175
+ assert.match(wf, /fetch-depth: 0/, 'a shallow clone makes the history scan a confident no-op');
176
+ });
@@ -49,8 +49,11 @@ test('a top-level key after steps ends the list', () => {
49
49
  });
50
50
 
51
51
  test('no frontmatter → empty contract', () => {
52
- assert.deepEqual(parseRoutineFrontmatter('just a body'), { mode: null, steps: [], description: null });
53
- assert.deepEqual(parseRoutineFrontmatter(''), { mode: null, steps: [], description: null });
52
+ // `cadence: null` joined the contract at task 1003209 — routine-schedule.js
53
+ // branches on its truthiness, so "absent" must be null, never undefined.
54
+ const empty = { mode: null, cadence: null, steps: [], description: null };
55
+ assert.deepEqual(parseRoutineFrontmatter('just a body'), empty);
56
+ assert.deepEqual(parseRoutineFrontmatter(''), empty);
54
57
  });
55
58
 
56
59
  test('mode-only frontmatter (judgment) → no steps', () => {