@memnexus-ai/mx-agent-cli 0.1.180 → 0.1.182
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/dist/__tests__/config-mirror-integrity.test.js +8 -0
- package/dist/__tests__/config-mirror-integrity.test.js.map +1 -1
- package/dist/__tests__/coordination-brief-pin.test.d.ts +20 -0
- package/dist/__tests__/coordination-brief-pin.test.d.ts.map +1 -0
- package/dist/__tests__/coordination-brief-pin.test.js +37 -0
- package/dist/__tests__/coordination-brief-pin.test.js.map +1 -0
- package/dist/agent-config/hooks/coordination-brief.sh +25 -0
- package/package.json +1 -1
|
@@ -153,6 +153,14 @@ const MIRROR_PAIRS = [
|
|
|
153
153
|
'.claude/hooks/coordination-brief.sh',
|
|
154
154
|
'mx-agent-system/agent-config/hooks/coordination-brief.sh',
|
|
155
155
|
],
|
|
156
|
+
// The co-located hook test suite. Not part of the shipped config surface
|
|
157
|
+
// (bundled-config excludes *.test.sh), but both dev copies are edited in
|
|
158
|
+
// lockstep — enforce byte-identity so the slug-validation tests can't drift
|
|
159
|
+
// (v2.40 QA finding, KI-COORDMT-HOOK-EXPORT-ROBUSTNESS).
|
|
160
|
+
[
|
|
161
|
+
'.claude/hooks/coordination-brief.test.sh',
|
|
162
|
+
'mx-agent-system/agent-config/hooks/coordination-brief.test.sh',
|
|
163
|
+
],
|
|
156
164
|
// NOTE: agent-config/settings.json is intentionally NOT a mirror pair — the
|
|
157
165
|
// worktree .claude/settings.json is COMPOSED/merged from the source, not a
|
|
158
166
|
// byte-identical copy, so its SessionStart wiring is verified by composition,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-mirror-integrity.test.js","sourceRoot":"","sources":["../../src/__tests__/config-mirror-integrity.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config-mirror-integrity.test.js","sourceRoot":"","sources":["../../src/__tests__/config-mirror-integrity.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KI-COORDMT-HOOK-EXPORT-ROBUSTNESS — publish-side sha pin for the session-start
|
|
3
|
+
* coordination-brief hook (Red Team v2.41 Step-6 Major).
|
|
4
|
+
*
|
|
5
|
+
* WHY HERE (defense in depth): the CLI publish workflow (mx-agent-cli-publish.yml)
|
|
6
|
+
* triggers on agent-config/** and BUNDLES agent-config/hooks/coordination-brief.sh
|
|
7
|
+
* into the published package (scripts/bundle-config.mjs). Its test gate is the CLI
|
|
8
|
+
* `npm test` suite. Without a pin assertion IN THIS SUITE, a PR that edits only the
|
|
9
|
+
* hook could ship an un-vetted hook in a new CLI even if someone later loosens the
|
|
10
|
+
* coordination-service workflow's path filters. This test makes that impossible:
|
|
11
|
+
* the CLI cannot go green — and therefore cannot publish — with a drifted hook.
|
|
12
|
+
*
|
|
13
|
+
* THREE PIN SITES MUST BUMP TOGETHER when coordination-brief.sh changes:
|
|
14
|
+
* 1. coordination-service/src/__tests__/coordination-brief-drift.test.ts (PINNED_SHA256)
|
|
15
|
+
* 2. cli/src/__tests__/coordination-brief-pin.test.ts (this file)
|
|
16
|
+
* 3. spearmint-private .github/workflows/coordination-hook-pin.yml (PINNED_SHA256)
|
|
17
|
+
* See the drift-test header for the full re-distribution procedure.
|
|
18
|
+
*/
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=coordination-brief-pin.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordination-brief-pin.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/coordination-brief-pin.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KI-COORDMT-HOOK-EXPORT-ROBUSTNESS — publish-side sha pin for the session-start
|
|
3
|
+
* coordination-brief hook (Red Team v2.41 Step-6 Major).
|
|
4
|
+
*
|
|
5
|
+
* WHY HERE (defense in depth): the CLI publish workflow (mx-agent-cli-publish.yml)
|
|
6
|
+
* triggers on agent-config/** and BUNDLES agent-config/hooks/coordination-brief.sh
|
|
7
|
+
* into the published package (scripts/bundle-config.mjs). Its test gate is the CLI
|
|
8
|
+
* `npm test` suite. Without a pin assertion IN THIS SUITE, a PR that edits only the
|
|
9
|
+
* hook could ship an un-vetted hook in a new CLI even if someone later loosens the
|
|
10
|
+
* coordination-service workflow's path filters. This test makes that impossible:
|
|
11
|
+
* the CLI cannot go green — and therefore cannot publish — with a drifted hook.
|
|
12
|
+
*
|
|
13
|
+
* THREE PIN SITES MUST BUMP TOGETHER when coordination-brief.sh changes:
|
|
14
|
+
* 1. coordination-service/src/__tests__/coordination-brief-drift.test.ts (PINNED_SHA256)
|
|
15
|
+
* 2. cli/src/__tests__/coordination-brief-pin.test.ts (this file)
|
|
16
|
+
* 3. spearmint-private .github/workflows/coordination-hook-pin.yml (PINNED_SHA256)
|
|
17
|
+
* See the drift-test header for the full re-distribution procedure.
|
|
18
|
+
*/
|
|
19
|
+
import { describe, it, expect } from 'vitest';
|
|
20
|
+
import { readFileSync } from 'node:fs';
|
|
21
|
+
import { createHash } from 'node:crypto';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
import { join, dirname } from 'node:path';
|
|
24
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
// cli/src/__tests__ → mx-agent-system/agent-config/hooks/coordination-brief.sh
|
|
26
|
+
const HOOK_FILE = join(here, '..', '..', '..', 'agent-config', 'hooks', 'coordination-brief.sh');
|
|
27
|
+
// Mirror of the platform PINNED_SHA256 (coordination-brief-drift.test.ts). Bump in
|
|
28
|
+
// lockstep with the other two pin sites named in the header above.
|
|
29
|
+
const PINNED_SHA256 = '3c636034e87f89efdb4d4b2cb270e73b2769710dde42651cdd9ee7d865028962';
|
|
30
|
+
describe('coordination-brief hook pin — publish-side gate (KI-COORDMT-HOOK-EXPORT-ROBUSTNESS)', () => {
|
|
31
|
+
it('the bundled hook matches its pinned sha256 (else the CLI must not publish)', () => {
|
|
32
|
+
const bytes = readFileSync(HOOK_FILE);
|
|
33
|
+
const actual = createHash('sha256').update(bytes).digest('hex');
|
|
34
|
+
expect(actual).toBe(PINNED_SHA256);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=coordination-brief-pin.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordination-brief-pin.test.js","sourceRoot":"","sources":["../../src/__tests__/coordination-brief-pin.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,+EAA+E;AAC/E,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,uBAAuB,CAAC,CAAC;AAEjG,mFAAmF;AACnF,mEAAmE;AACnE,MAAM,aAAa,GAAG,kEAAkE,CAAC;AAEzF,QAAQ,CAAC,qFAAqF,EAAE,GAAG,EAAE;IACnG,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAChE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -95,8 +95,33 @@ PROJECT="${MX_PRODUCT_SLUG:-}"
|
|
|
95
95
|
if [ -z "$PROJECT" ] && [ -f "${WORKTREE}/mx-agent.config.json" ]; then
|
|
96
96
|
PROJECT="$(node -e 'try{const c=require(process.argv[1]);const s=(c.projectSlug||(c.project&&c.project.slug)||"");process.stdout.write(String(s).trim())}catch(e){}' "${WORKTREE}/mx-agent.config.json" 2>/dev/null || true)"
|
|
97
97
|
fi
|
|
98
|
+
# Unset/empty → default memnexus (unchanged behavior). A set-but-INVALID slug is
|
|
99
|
+
# NEVER coerced to memnexus — that would silently run the wrong tenant's brief.
|
|
98
100
|
[ -z "$PROJECT" ] && PROJECT="$DEFAULT_PROJECT"
|
|
99
101
|
|
|
102
|
+
# ── KI-COORDMT-HOOK-EXPORT-ROBUSTNESS: validate the resolved slug fail-closed. ─
|
|
103
|
+
# Mirror coordination-service isValidSlug (types.ts): base regex
|
|
104
|
+
# ^[a-z][a-z0-9-]{0,48}[a-z0-9]$, NO '--' substring (KV name parse-safety), and
|
|
105
|
+
# NOT the reserved word 'all'. A resolved-but-invalid PROJECT skips the brief with
|
|
106
|
+
# a one-line stderr warning (fail-closed) — it is never coerced to a default and
|
|
107
|
+
# never flows into the az secret-name / roster lookup below. "$PROJECT" is quoted.
|
|
108
|
+
is_valid_slug() {
|
|
109
|
+
local s="$1"
|
|
110
|
+
case "$s" in
|
|
111
|
+
*--*) return 1 ;; # no '--' (double-hyphen is the KV name separator)
|
|
112
|
+
all) return 1 ;; # reserved broadcast slug
|
|
113
|
+
esac
|
|
114
|
+
# Base regex, WHOLE-STRING: bash `[[ =~ ]]` anchors ^/$ to the string ends, so a
|
|
115
|
+
# multiline value (e.g. $'memnexus\nevil') fails — unlike `grep -Eq`, which
|
|
116
|
+
# matches line-by-line and would accept an embedded newline. Starts lowercase
|
|
117
|
+
# alpha, then [a-z0-9-], ends alnum; 2..50 chars.
|
|
118
|
+
[[ "$s" =~ ^[a-z][a-z0-9-]{0,48}[a-z0-9]$ ]]
|
|
119
|
+
}
|
|
120
|
+
if ! is_valid_slug "$PROJECT"; then
|
|
121
|
+
echo "coordination brief: resolved project slug \"$PROJECT\" is invalid — skipping (fail-closed)" >&2
|
|
122
|
+
exit 0
|
|
123
|
+
fi
|
|
124
|
+
|
|
100
125
|
# ── SF-2: per-project roster-membership validation before any az call. ───────
|
|
101
126
|
# The roster is read from the OFFLINE generated file (ND-2), with the builtin
|
|
102
127
|
# memnexus roster as an offline fallback. NEVER a live GET /roster.
|