fix(redaction): omit remaining configuration values from refusals (#1873)
This commit is contained in:
1 parent
ddf4f895cd
commit
c8ff8ea128
34 files changed
+638
-198
No files matched your search
+11
-11
@@ -195,11 +195,11 @@ function validateDataRoot(value, file) {
|
||||
fail(2, 'execution "dataRoot" contains a NUL byte');
|
||||
}
|
||||
if (!path.isAbsolute(value)) {
|
||||
fail(2, `execution "dataRoot" must be an absolute path (got "${value}")`);
|
||||
fail(2, `execution "dataRoot" must be an absolute path`);
|
||||
}
|
||||
const resolved = path.resolve(value);
|
||||
if (resolved !== value) {
|
||||
fail(2, `execution "dataRoot" must be canonical without ".", "..", trailing slashes, or redundant separators (got "${value}")`);
|
||||
fail(2, `execution "dataRoot" must be canonical without ".", "..", trailing slashes, or redundant separators`);
|
||||
}
|
||||
if (resolved === path.parse(resolved).root) {
|
||||
fail(2, 'execution "dataRoot" must not be the filesystem root');
|
||||
@@ -252,7 +252,7 @@ function validateFederationOrigin(value, where) {
|
||||
url = null;
|
||||
}
|
||||
if (url === null || url.protocol !== "https:" || url.origin !== value) {
|
||||
fail(2, `${where} must be an https origin with no path, query, or userinfo (got ${JSON.stringify(value)})`);
|
||||
fail(2, `${where} must be an https origin with no path, query, or userinfo`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ function validateFederation(value) {
|
||||
}
|
||||
rejectUnknownKeys(value, ["self", "peers"], "federation");
|
||||
if (typeof value.self !== "string" || !FEDERATION_ID_PATTERN.test(value.self)) {
|
||||
fail(2, `federation.self must match ${FEDERATION_ID_PATTERN} (got ${JSON.stringify(value.self)})`);
|
||||
fail(2, `federation.self must match ${FEDERATION_ID_PATTERN}`);
|
||||
}
|
||||
if (!Array.isArray(value.peers)) {
|
||||
fail(2, 'federation.peers must be an array');
|
||||
@@ -275,10 +275,10 @@ function validateFederation(value) {
|
||||
}
|
||||
rejectUnknownKeys(peer, ["id", "origin", "label"], where);
|
||||
if (typeof peer.id !== "string" || !FEDERATION_ID_PATTERN.test(peer.id)) {
|
||||
fail(2, `${where}.id must match ${FEDERATION_ID_PATTERN} (got ${JSON.stringify(peer.id)})`);
|
||||
fail(2, `${where}.id must match ${FEDERATION_ID_PATTERN}`);
|
||||
}
|
||||
if (ids.has(peer.id)) {
|
||||
fail(2, `${where}.id ${JSON.stringify(peer.id)} is already named (by federation.self or an earlier peer)`);
|
||||
fail(2, `${where}.id is already named (by federation.self or an earlier peer)`);
|
||||
}
|
||||
ids.add(peer.id);
|
||||
validateFederationOrigin(peer.origin, `${where}.origin`);
|
||||
@@ -306,10 +306,10 @@ async function validate(document, file) {
|
||||
);
|
||||
|
||||
if (document.configVersion !== SUPPORTED_CONFIG_VERSION) {
|
||||
fail(2, `unsupported configVersion: ${JSON.stringify(document.configVersion)} (supported: ${SUPPORTED_CONFIG_VERSION})`);
|
||||
fail(2, `unsupported configVersion: (supported: ${SUPPORTED_CONFIG_VERSION})`);
|
||||
}
|
||||
if (!SUPPORTED_ENVIRONMENTS.has(document.environment)) {
|
||||
fail(2, `unsupported environment: ${JSON.stringify(document.environment)} (supported: ${[...SUPPORTED_ENVIRONMENTS].join(", ")})`);
|
||||
fail(2, `unsupported environment: (supported: ${[...SUPPORTED_ENVIRONMENTS].join(", ")})`);
|
||||
}
|
||||
|
||||
const dataRoot = validateDataRoot(document.dataRoot, file);
|
||||
@@ -319,12 +319,12 @@ async function validate(document, file) {
|
||||
}
|
||||
rejectUnknownKeys(document.execution, ["backend", "provider", "model", "adapter"], '"execution"');
|
||||
if (!SUPPORTED_BACKENDS.has(document.execution.backend)) {
|
||||
fail(2, `unsupported execution.backend: ${JSON.stringify(document.execution.backend)} (supported: ${[...SUPPORTED_BACKENDS].join(", ")})`);
|
||||
fail(2, `unsupported execution.backend: (supported: ${[...SUPPORTED_BACKENDS].join(", ")})`);
|
||||
}
|
||||
for (const key of ["provider", "model"]) {
|
||||
const value = document.execution[key];
|
||||
if (typeof value !== "string" || !NAME_PATTERN.test(value)) {
|
||||
fail(2, `execution.${key} must match ${NAME_PATTERN} (got ${JSON.stringify(value)})`);
|
||||
fail(2, `execution.${key} must match ${NAME_PATTERN}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ async function validate(document, file) {
|
||||
? "pi"
|
||||
: document.execution.adapter;
|
||||
if (typeof adapter !== "string" || !SUPPORTED_ADAPTERS.has(adapter)) {
|
||||
fail(2, `unsupported execution.adapter: ${JSON.stringify(adapter)} (supported: ${[...SUPPORTED_ADAPTERS].join(", ")})`);
|
||||
fail(2, `unsupported execution.adapter: (supported: ${[...SUPPORTED_ADAPTERS].join(", ")})`);
|
||||
}
|
||||
|
||||
// Last, so the older checks keep their order. The key is in the output only when the file has
|
||||
|
||||
@@ -84,7 +84,7 @@ function readJsonFile(file, what) {
|
||||
|
||||
function validateId(value, what) {
|
||||
if (typeof value !== "string" || !ID_PATTERN.test(value)) {
|
||||
fail(2, `${what} must match ${ID_PATTERN} (got ${JSON.stringify(value)})`);
|
||||
fail(2, `${what} must match ${ID_PATTERN}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -93,7 +93,7 @@ function validateMission(document, file) {
|
||||
if (!isPlainObject(document)) fail(2, "mission must be a JSON object");
|
||||
rejectUnknownKeys(document, ["missionVersion", "id", "objective", "directives", "capabilities"], "mission");
|
||||
if (document.missionVersion !== 1) {
|
||||
fail(2, `unsupported missionVersion: ${JSON.stringify(document.missionVersion)} (supported: 1)`);
|
||||
fail(2, `unsupported missionVersion: (supported: 1)`);
|
||||
}
|
||||
validateId(document.id, "mission id");
|
||||
if (typeof document.objective !== "string" || document.objective.trim().length === 0 || document.objective.length > 4000) {
|
||||
@@ -123,9 +123,9 @@ function validateMission(document, file) {
|
||||
const seen = new Set();
|
||||
for (const tool of document.capabilities.tools) {
|
||||
if (!SUPPORTED_TOOLS.includes(tool)) {
|
||||
fail(2, `unsupported mission tool: ${JSON.stringify(tool)} (supported: ${SUPPORTED_TOOLS.join(", ")})`);
|
||||
fail(2, `unsupported mission tool: (supported: ${SUPPORTED_TOOLS.join(", ")})`);
|
||||
}
|
||||
if (seen.has(tool)) fail(2, `duplicate tool in mission capabilities.tools: ${tool}`);
|
||||
if (seen.has(tool)) fail(2, `duplicate tool in mission capabilities.tools`);
|
||||
seen.add(tool);
|
||||
}
|
||||
capabilities = { tools: [...seen] };
|
||||
@@ -138,7 +138,7 @@ function validateTask(document, file) {
|
||||
if (!isPlainObject(document)) fail(2, "task must be a JSON object");
|
||||
rejectUnknownKeys(document, ["taskVersion", "id", "prompt", "mission", "expectExact", "timeoutSeconds", "workspace", "capabilities", "session", "sessionForkFrom"], "task");
|
||||
if (document.taskVersion !== 1) {
|
||||
fail(2, `unsupported taskVersion: ${JSON.stringify(document.taskVersion)} (supported: 1)`);
|
||||
fail(2, `unsupported taskVersion: (supported: 1)`);
|
||||
}
|
||||
validateId(document.id, "task id");
|
||||
|
||||
@@ -228,9 +228,9 @@ function validateTask(document, file) {
|
||||
const seen = new Set();
|
||||
for (const tool of document.capabilities.tools) {
|
||||
if (!SUPPORTED_TOOLS.includes(tool)) {
|
||||
fail(2, `unsupported tool: ${JSON.stringify(tool)} (supported: ${SUPPORTED_TOOLS.join(", ")})`);
|
||||
fail(2, `unsupported tool: (supported: ${SUPPORTED_TOOLS.join(", ")})`);
|
||||
}
|
||||
if (seen.has(tool)) fail(2, `duplicate tool in capabilities.tools: ${tool}`);
|
||||
if (seen.has(tool)) fail(2, `duplicate tool in capabilities.tools`);
|
||||
seen.add(tool);
|
||||
}
|
||||
tools = [...seen];
|
||||
|
||||
@@ -238,7 +238,7 @@ expect_fed_refusal "federation peer id pattern exits 2 naming the key" "federati
|
||||
FED_LONG_LABEL="$(printf 'x%.0s' $(seq 81))"
|
||||
expect_fed_refusal "federation peer label over 80 characters exits 2 naming the key" "federation.peers[0].label" \
|
||||
'{"self":"hub","peers":[{"id":"factory","origin":"https://mosaic.woltje.com","label":"'"$FED_LONG_LABEL"'"}]}'
|
||||
expect_fed_refusal "federation duplicate peer id exits 2 naming the key" 'federation.peers[1].id "factory" is already named' \
|
||||
expect_fed_refusal "federation duplicate peer id exits 2 naming the key" 'federation.peers[1].id is already named' \
|
||||
'{"self":"hub","peers":[{"id":"factory","origin":"https://mosaic.woltje.com","label":"F"},{"id":"factory","origin":"https://other.woltje.com","label":"G"}]}'
|
||||
expect_fed_refusal "federation peer origin with a trailing slash exits 2 naming the key" "federation.peers[0].origin" \
|
||||
'{"self":"hub","peers":[{"id":"factory","origin":"https://mosaic.woltje.com/","label":"F"}]}'
|
||||
|
||||
@@ -317,7 +317,7 @@ EOF
|
||||
&& printf '%s\n' "$V2_OUT" | grep -q '^MOSAIC_ROLE_NETWORK=api-only$' || V2_OK=1
|
||||
done
|
||||
check "shipped version 2 roles resolve with their contracts (pm, cto, coder, reviewer)" "$V2_OK"
|
||||
printf '# v2\n' > "$SANDBOX/roles/v2.md"
|
||||
printf '# v2\n\n## Authority\n' > "$SANDBOX/roles/v2.md"
|
||||
v2role() { # v2role NAME AUTHORITY_JSON CREDENTIALS_JSON [CONTRACT]
|
||||
printf '{"roleVersion":2,"name":"%s","title":"T","contract":"%s","tools":["read"],"network":"none","authority":%s,"credentials":%s}' \
|
||||
"$1" "${4:-v2.md}" "$2" "$3" > "$SANDBOX/roles/$1.json"
|
||||
|
||||
Reference in new issue
Block a user