@arjunkhera/atlas 0.4.44 → 0.4.45
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/.claude-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/shape/check.mjs +39 -3
- package/shape/releases.json +5 -0
package/package.json
CHANGED
package/shape/check.mjs
CHANGED
|
@@ -38,7 +38,7 @@ export const sha256 = (text) => createHash('sha256').update(String(text ?? ''),
|
|
|
38
38
|
// Whether a copy is current or behind is not decided here. CI has no package
|
|
39
39
|
// and no network. The session verb decides it, from the release list that
|
|
40
40
|
// ships beside this file in the package, shape/releases.json.
|
|
41
|
-
export const CHECK_VERSION =
|
|
41
|
+
export const CHECK_VERSION = 9;
|
|
42
42
|
|
|
43
43
|
// ---------------------------------------------------------------------------
|
|
44
44
|
// The spec. One object per version. The check reads a version it has here and
|
|
@@ -1550,6 +1550,33 @@ export function counts(files) {
|
|
|
1550
1550
|
// check version 6 five cases switched the rule off and printed a warning that
|
|
1551
1551
|
// a person merges the file. Nothing switches it off now. The base copy scores,
|
|
1552
1552
|
// and the base kind and spec score both trees, so no case needs to.
|
|
1553
|
+
// A head whose atlas.yaml names a spec that this copy of the check cannot
|
|
1554
|
+
// read. A head with no spec, or with an atlas.yaml that does not read, is not
|
|
1555
|
+
// one: those stay errors.
|
|
1556
|
+
export function headSpecUnread(facts) {
|
|
1557
|
+
const spec = facts?.spec;
|
|
1558
|
+
return spec !== undefined && spec !== null && spec !== '' && !Object.hasOwn(SPECS, String(spec));
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
// The head of a move to a newer spec: no part is scored, but every file the
|
|
1562
|
+
// newer spec can read for facts is swept for secrets. That is atlas.yaml, each
|
|
1563
|
+
// file under atlas/, and each facts file that atlas.yaml points to by a plain
|
|
1564
|
+
// path. The trust checks of the pattern list and the owner_only checks run as
|
|
1565
|
+
// in scan, so a newer spec cannot turn either of them from red into owner.
|
|
1566
|
+
export function sweepHead({ root, repoId = null, secretPatterns: patterns = secretPatterns() }) {
|
|
1567
|
+
const { facts } = readFacts(root);
|
|
1568
|
+
const errors = [...ownerOnlyErrors(facts)];
|
|
1569
|
+
const usable = Array.isArray(patterns) && patterns.every((pattern) => pattern instanceof RegExp) ? patterns : [];
|
|
1570
|
+
if (!usable.length) errors.push('the secret pattern list is empty or is not a list of patterns, so a credential value could not be caught; this check cannot be trusted');
|
|
1571
|
+
const missed = canaryMisses();
|
|
1572
|
+
if (missed.length) errors.push(`${missed.length} secret pattern(s) no longer catch their own canary: ${missed.join(', ')}; this check cannot be trusted`);
|
|
1573
|
+
const context = { root, secretPatterns: usable, errors };
|
|
1574
|
+
const files = facts?.files && typeof facts.files === 'object' && !Array.isArray(facts.files) ? facts.files : {};
|
|
1575
|
+
const pointed = Object.values(files).filter((path) => plainPath(path) && isFile(root, path));
|
|
1576
|
+
for (const path of new Set(['atlas.yaml', ...walk(root, 'atlas'), ...pointed])) secretIn(context, path, readText(root, path));
|
|
1577
|
+
return { ok: false, check_version: CHECK_VERSION, repo: repoId, kind: null, spec: facts?.spec ?? null, swept_only: true, files: [], by_reference: [], counts: counts([]), errors };
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1553
1580
|
export const OWNER_CASES = Object.freeze(['check-file', 'workflow', 'kind', 'spec', 'moved', 'first-run']);
|
|
1554
1581
|
|
|
1555
1582
|
const fileHash = (root, path) => { const text = readText(root, path); return text === null ? null : sha256(text); };
|
|
@@ -1633,8 +1660,9 @@ export function noLoss({ headRoot, baseRoot, baseSha = null, baseCommit = null,
|
|
|
1633
1660
|
if (String(out.head_facts.kind) !== String(scoreAs.kind)) {
|
|
1634
1661
|
owner('kind', `atlas.yaml names kind "${scoreAs.kind}" at the base and "${out.head_facts.kind}" at the head; this pull request changes which parts the repo needs`);
|
|
1635
1662
|
}
|
|
1663
|
+
const unread = Object.hasOwn(SPECS, String(scoreAs.spec)) && headSpecUnread(headRead.facts);
|
|
1636
1664
|
if (String(out.head_facts.spec) !== String(scoreAs.spec)) {
|
|
1637
|
-
owner('spec', `atlas.yaml names spec "${scoreAs.spec}" at the base and "${out.head_facts.spec}" at the head; this pull request changes what the spec version means`);
|
|
1665
|
+
owner('spec', `atlas.yaml names spec "${scoreAs.spec}" at the base and "${out.head_facts.spec}" at the head; this pull request changes what the spec version means${unread ? `; this copy of the check, check version ${CHECK_VERSION}, cannot read spec "${out.head_facts.spec}", so it did not score the head and only swept it for secrets` : ''}`);
|
|
1638
1666
|
}
|
|
1639
1667
|
|
|
1640
1668
|
// 3. Does the diff change the gate itself? The base copy judges, so the
|
|
@@ -1645,6 +1673,12 @@ export function noLoss({ headRoot, baseRoot, baseSha = null, baseCommit = null,
|
|
|
1645
1673
|
}
|
|
1646
1674
|
}
|
|
1647
1675
|
|
|
1676
|
+
// A head on a spec this copy cannot read is a move to a newer spec. This
|
|
1677
|
+
// copy has no yardstick for the head, so it compares nothing. The spec row
|
|
1678
|
+
// above sends it to the owner, and the gate still sweeps the head for
|
|
1679
|
+
// secrets (roadmap R62: the base copy judged the move to spec 3 red).
|
|
1680
|
+
if (unread) return out;
|
|
1681
|
+
|
|
1648
1682
|
// 4. Score both trees, by the same yardstick, and compare part by part. The
|
|
1649
1683
|
// head is scored twice: at its own pointers, and at the base's.
|
|
1650
1684
|
const base = scan({ root: baseRoot, repoId, secretPatterns: patterns, scoreAs });
|
|
@@ -1988,7 +2022,9 @@ export function gateFromGit({ git, baseCommit, headCommit, repoId = null, trees
|
|
|
1988
2022
|
}
|
|
1989
2023
|
mkdirSync(baseRoot, { recursive: true });
|
|
1990
2024
|
mkdirSync(headRoot, { recursive: true });
|
|
1991
|
-
const
|
|
2025
|
+
const baseFacts = readFacts(baseRoot).facts;
|
|
2026
|
+
const swept = baseFacts && Object.hasOwn(SPECS, String(baseFacts.spec)) && headSpecUnread(readFacts(headRoot).facts);
|
|
2027
|
+
const report = swept ? sweepHead({ root: headRoot, repoId, secretPatterns: patterns }) : scan({ root: headRoot, repoId, secretPatterns: patterns });
|
|
1992
2028
|
const state = noLoss({ headRoot, baseRoot, baseCommit: mergeBase, repoId, secretPatterns: patterns });
|
|
1993
2029
|
// A link or a submodule that the head adds or changes is never read, so the
|
|
1994
2030
|
// check cannot judge it. The owner reads it.
|
package/shape/releases.json
CHANGED
|
@@ -47,6 +47,11 @@
|
|
|
47
47
|
"check_version": 8,
|
|
48
48
|
"sha256": "8cf521f6e8f89ae65a257c521c583281e0c3c27ef968b4bd96eb336a8d095795",
|
|
49
49
|
"workflow_sha256": "fcddebef030e6564f97e1a5fb81c8ad1b3084ebef9622167c6565698312dcdd7"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"check_version": 9,
|
|
53
|
+
"sha256": "87896abfc09afd22724cfa645bbb5ef029d83887caf70f38b88d00b21cddef02",
|
|
54
|
+
"workflow_sha256": "fcddebef030e6564f97e1a5fb81c8ad1b3084ebef9622167c6565698312dcdd7"
|
|
50
55
|
}
|
|
51
56
|
]
|
|
52
57
|
}
|