mustflow 2.26.0 → 2.28.0
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/README.md +2 -2
- package/dist/cli/lib/run-plan.js +11 -3
- package/dist/core/command-contract-validation.js +15 -12
- package/dist/core/command-env.js +43 -0
- package/dist/core/command-intent-eligibility.js +2 -1
- package/dist/core/contract-lint.js +2 -1
- package/package.json +1 -1
- package/schemas/commands.schema.json +4 -1
- package/templates/default/common/.mustflow/config/commands.toml +1 -0
- package/templates/default/i18n.toml +7 -1
- package/templates/default/locales/en/.mustflow/skills/INDEX.md +2 -1
- package/templates/default/locales/en/.mustflow/skills/docker-code-change/SKILL.md +262 -0
- package/templates/default/locales/en/.mustflow/skills/routes.toml +6 -0
- package/templates/default/manifest.toml +8 -1
package/README.md
CHANGED
|
@@ -307,9 +307,9 @@ Runnable work is declared in `.mustflow/config/commands.toml` so agents do not g
|
|
|
307
307
|
- `run_policy = "agent_allowed"`
|
|
308
308
|
- `stdin = "closed"`
|
|
309
309
|
|
|
310
|
-
Development servers, watch modes, browser UIs, interactive commands, and background processes do not run directly. `mf run` also rejects obvious long-running `argv` shapes, such as shell-wrapper background payloads, interpreter loops, package-manager development scripts, watchers, and development servers declared as one-shot commands.
|
|
310
|
+
Development servers, watch modes, browser UIs, interactive commands, and background processes do not run directly. `mf run` also rejects obvious long-running `argv` shapes, such as shell-wrapper background payloads, interpreter loops, package-manager development scripts, watchers, and development servers declared as one-shot commands. If a bounded one-shot command has a name that matches a common long-running pattern, the intent can explicitly acknowledge that with `allow_long_running_command_patterns = true`; background shell patterns remain blocked.
|
|
311
311
|
|
|
312
|
-
Command environments remove the project-local `node_modules/.bin` path from `PATH` by default. If an intent needs a project dependency binary such as `eslint`, `tsc`, or `vitest`, declare it through the package manager, for example `npm exec eslint -- ...`, `pnpm exec tsc -- --noEmit`, `bun x eslint ...`, or `yarn exec eslint ...`. `mf check --strict` warns when an agent-runnable intent uses a bare executable name that appears under the project-local `.bin` directory.
|
|
312
|
+
Command environments remove the project-local `node_modules/.bin` path from `PATH` by default. If an intent needs a project dependency binary such as `eslint`, `tsc`, or `vitest`, declare it through the package manager, for example `npm exec eslint -- ...`, `pnpm exec tsc -- --noEmit`, `bun x eslint ...`, or `yarn exec eslint ...`. `mf check --strict` warns when an agent-runnable intent uses a bare executable name that appears under the project-local `.bin` directory, except for names listed in `defaults.allow_project_local_bin_bare_executables`. `mf run` may resolve those allowed names directly from the local `.bin` directory without exposing every local binary through `PATH`. The installed template allows `mf` and `mustflow` by default. Intent-level `allow_env_inheritance_risks = true` is available when a command intentionally uses `env_policy = "inherit"`.
|
|
313
313
|
|
|
314
314
|
Use `mf verify --reason <event> --plan-only --json` to inspect matching verification intents, command eligibility, remaining gaps, and missing runnable coverage without executing commands. Use `mf run <intent> --dry-run --json` to inspect one resolved command intent without spawning a process or writing a run receipt. Plan-only verification includes a `decision_graph` that connects changed surfaces, classification reasons, command candidates, eligibility checks, effects, and gaps. When `.mustflow/cache/mustflow.sqlite` is fresh, scheduled entries also include read-only `effectGraph` metadata for write locks and lock conflicts. These graph rows are marked `explanation_only` and never grant command authority; `.mustflow/config/commands.toml` remains the only runnable command source.
|
|
315
315
|
|
package/dist/cli/lib/run-plan.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { isMustflowBinName } from '../../core/command-classification.js';
|
|
3
3
|
import { resolveSafeProjectCwd } from '../../core/command-cwd.js';
|
|
4
|
-
import { resolveCommandEnv } from '../../core/command-env.js';
|
|
4
|
+
import { readProjectLocalBinBareExecutableAllowlist, resolveAllowedProjectLocalBinExecutable, resolveCommandEnv, } from '../../core/command-env.js';
|
|
5
5
|
import { getCommandMaxOutputBytesLimitDetail, readEffectiveCommandCwd, readEffectiveCommandMaxOutputBytes, } from '../../core/command-run-constraints.js';
|
|
6
6
|
import { evaluateCommandIntentEligibility, } from '../../core/command-intent-eligibility.js';
|
|
7
7
|
import { inspectActiveRunLocks, } from '../../core/active-run-locks.js';
|
|
@@ -56,7 +56,7 @@ function resolveCurrentCliEntrypoint() {
|
|
|
56
56
|
const entrypoint = process.argv[1];
|
|
57
57
|
return entrypoint ? path.resolve(entrypoint) : undefined;
|
|
58
58
|
}
|
|
59
|
-
function resolveArgvCommand(intent, commandArgv) {
|
|
59
|
+
function resolveArgvCommand(projectRoot, contract, intent, commandArgv) {
|
|
60
60
|
const [command = '', ...args] = commandArgv;
|
|
61
61
|
if (isMustflowBuiltinIntent(intent) && isMustflowBinName(command)) {
|
|
62
62
|
const entrypoint = resolveCurrentCliEntrypoint();
|
|
@@ -68,6 +68,14 @@ function resolveArgvCommand(intent, commandArgv) {
|
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
+
const localBinExecutable = resolveAllowedProjectLocalBinExecutable(projectRoot, command, readProjectLocalBinBareExecutableAllowlist(contract));
|
|
72
|
+
if (localBinExecutable) {
|
|
73
|
+
return {
|
|
74
|
+
executable: localBinExecutable,
|
|
75
|
+
args,
|
|
76
|
+
shell: shouldUseShellForArgvExecutable(localBinExecutable),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
71
79
|
return {
|
|
72
80
|
executable: command,
|
|
73
81
|
args,
|
|
@@ -212,7 +220,7 @@ export function createRunPlan(projectRoot, contract, intentName, options = {}) {
|
|
|
212
220
|
commandArgv,
|
|
213
221
|
shellCommand: metadata.shellCommand,
|
|
214
222
|
mode: metadata.mode,
|
|
215
|
-
argvCommand: commandArgv ? resolveArgvCommand(rawIntent, commandArgv) : undefined,
|
|
223
|
+
argvCommand: commandArgv ? resolveArgvCommand(projectRoot, contract, rawIntent, commandArgv) : undefined,
|
|
216
224
|
writes: metadata.writes,
|
|
217
225
|
effects: metadata.effects,
|
|
218
226
|
network: metadata.network,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import { COMMAND_LIFECYCLES, COMMAND_RUN_POLICIES, LONG_RUNNING_LIFECYCLES, isRecord, readStringArray, } from './config-loading.js';
|
|
4
|
-
import { COMMAND_ENV_POLICIES, DEFAULT_COMMAND_ENV_POLICY } from './command-env.js';
|
|
3
|
+
import { COMMAND_ENV_POLICIES, DEFAULT_COMMAND_ENV_POLICY, PROJECT_LOCAL_BIN_BARE_EXECUTABLE_ALLOWLIST_KEY, normalizeCommandExecutableName, readProjectLocalBinBareExecutableAllowlist, resolveAllowedProjectLocalBinExecutable, } from './command-env.js';
|
|
5
4
|
import { COMMAND_EFFECT_CONCURRENCY, COMMAND_EFFECT_MODES, COMMAND_EFFECT_TYPES, validateCommandEffectLockWarnings, validateCommandEffects, } from './command-effects.js';
|
|
6
5
|
import { COMMAND_PRECONDITION_KINDS } from './command-preconditions.js';
|
|
7
6
|
import { commandIntentBlockedCommandPattern, commandIntentHasCommandSource, commandIntentNameIsSafe, } from './command-contract-rules.js';
|
|
@@ -13,6 +12,8 @@ const COMMAND_ARGV_PLACEHOLDER_PATTERN = /^\{([a-z][a-z0-9_]*)\}$/u;
|
|
|
13
12
|
const COMMAND_ARGV_MIXED_PLACEHOLDER_PATTERN = /\{([a-z][a-z0-9_]*)\}/u;
|
|
14
13
|
const WINDOWS_RESERVED_PATH_SEGMENTS = /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\..*)?$/iu;
|
|
15
14
|
const SAFE_PATH_EXTENSION_PATTERN = /^\.[A-Za-z0-9][A-Za-z0-9._-]*$/u;
|
|
15
|
+
const ALLOW_ENV_INHERITANCE_RISKS_KEY = 'allow_env_inheritance_risks';
|
|
16
|
+
const ALLOW_LONG_RUNNING_COMMAND_PATTERNS_KEY = 'allow_long_running_command_patterns';
|
|
16
17
|
function commandContractIssue(message, id) {
|
|
17
18
|
return id ? { id, message } : { message };
|
|
18
19
|
}
|
|
@@ -257,6 +258,7 @@ function validateCommandDefaults(commandsToml, issues) {
|
|
|
257
258
|
validateStringField(defaults, 'on_timeout', '[commands.defaults].on_timeout', issues);
|
|
258
259
|
validateAllowedStringField(defaults, 'env_policy', '[commands.defaults].env_policy', COMMAND_ENV_POLICIES, issues);
|
|
259
260
|
validateStringArrayField(defaults, 'env_allowlist', '[commands.defaults].env_allowlist', issues);
|
|
261
|
+
validateStringArrayField(defaults, PROJECT_LOCAL_BIN_BARE_EXECUTABLE_ALLOWLIST_KEY, `[commands.defaults].${PROJECT_LOCAL_BIN_BARE_EXECUTABLE_ALLOWLIST_KEY}`, issues);
|
|
260
262
|
validatePositiveIntegerField(defaults, 'default_timeout_seconds', '[commands.defaults].default_timeout_seconds', issues);
|
|
261
263
|
validateMaxOutputBytesField(defaults, 'max_output_bytes', '[commands.defaults].max_output_bytes', issues);
|
|
262
264
|
validatePositiveIntegerField(defaults, 'kill_after_seconds', '[commands.defaults].kill_after_seconds', issues);
|
|
@@ -337,6 +339,8 @@ function validateCommandIntent(intentName, intent, allIntents, issues) {
|
|
|
337
339
|
validateAllowedStringField(intent, 'env_policy', `[commands.intents.${intentName}].env_policy`, COMMAND_ENV_POLICIES, issues);
|
|
338
340
|
validateBooleanField(intent, 'allow_shell', `[commands.intents.${intentName}].allow_shell`, issues);
|
|
339
341
|
validateStringArrayField(intent, 'env_allowlist', `[commands.intents.${intentName}].env_allowlist`, issues);
|
|
342
|
+
validateBooleanField(intent, ALLOW_ENV_INHERITANCE_RISKS_KEY, `[commands.intents.${intentName}].${ALLOW_ENV_INHERITANCE_RISKS_KEY}`, issues);
|
|
343
|
+
validateBooleanField(intent, ALLOW_LONG_RUNNING_COMMAND_PATTERNS_KEY, `[commands.intents.${intentName}].${ALLOW_LONG_RUNNING_COMMAND_PATTERNS_KEY}`, issues);
|
|
340
344
|
validateMaxOutputBytesField(intent, 'max_output_bytes', `[commands.intents.${intentName}].max_output_bytes`, issues);
|
|
341
345
|
validatePositiveIntegerField(intent, 'kill_after_seconds', `[commands.intents.${intentName}].kill_after_seconds`, issues);
|
|
342
346
|
validateCommandIntentSelection(intentName, intent, issues);
|
|
@@ -375,7 +379,7 @@ function validateCommandIntent(intentName, intent, allIntents, issues) {
|
|
|
375
379
|
if (blockedCommandPattern?.code === 'shell_background_pattern') {
|
|
376
380
|
issues.push(commandContractIssue(`Shell intent ${intentName} contains a blocked long-running or background pattern`, 'mustflow.command_contract.shell_background_pattern'));
|
|
377
381
|
}
|
|
378
|
-
if (blockedCommandPattern?.code === 'long_running_command_pattern') {
|
|
382
|
+
if (blockedCommandPattern?.code === 'long_running_command_pattern' && intent[ALLOW_LONG_RUNNING_COMMAND_PATTERNS_KEY] !== true) {
|
|
379
383
|
issues.push(commandContractIssue(`Intent ${intentName} contains a blocked long-running or background command pattern`, 'mustflow.command_contract.long_running_command_pattern'));
|
|
380
384
|
}
|
|
381
385
|
if (hasOwn(intent, 'success_exit_codes')) {
|
|
@@ -419,6 +423,9 @@ export function findCommandEnvInheritanceWarnings(commandsToml) {
|
|
|
419
423
|
if (envPolicy.policy !== 'inherit') {
|
|
420
424
|
continue;
|
|
421
425
|
}
|
|
426
|
+
if (intent[ALLOW_ENV_INHERITANCE_RISKS_KEY] === true) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
422
429
|
const reasons = readCommandEnvInheritanceRiskReasons(intent);
|
|
423
430
|
warnings.push({
|
|
424
431
|
intentName,
|
|
@@ -465,21 +472,14 @@ function validateCommandEnvInheritanceWarnings(commandsToml) {
|
|
|
465
472
|
return issues;
|
|
466
473
|
}
|
|
467
474
|
function projectLocalBinExecutableExists(projectRoot, executable) {
|
|
468
|
-
|
|
469
|
-
const executableName = path.basename(executable).replace(/\.(?:cmd|exe|ps1)$/iu, '');
|
|
470
|
-
const candidates = [
|
|
471
|
-
executableName,
|
|
472
|
-
`${executableName}.cmd`,
|
|
473
|
-
`${executableName}.exe`,
|
|
474
|
-
`${executableName}.ps1`,
|
|
475
|
-
];
|
|
476
|
-
return candidates.some((candidate) => existsSync(path.join(localBinPath, candidate)));
|
|
475
|
+
return resolveAllowedProjectLocalBinExecutable(projectRoot, executable, new Set([normalizeCommandExecutableName(executable)])) !== null;
|
|
477
476
|
}
|
|
478
477
|
function validateProjectLocalBinWarnings(projectRoot, commandsToml) {
|
|
479
478
|
const issues = [];
|
|
480
479
|
if (!isRecord(commandsToml?.intents)) {
|
|
481
480
|
return issues;
|
|
482
481
|
}
|
|
482
|
+
const allowedBareExecutables = readProjectLocalBinBareExecutableAllowlist(commandsToml);
|
|
483
483
|
for (const [intentName, intent] of Object.entries(commandsToml.intents)) {
|
|
484
484
|
if (!isRecord(intent)) {
|
|
485
485
|
continue;
|
|
@@ -492,6 +492,9 @@ function validateProjectLocalBinWarnings(projectRoot, commandsToml) {
|
|
|
492
492
|
if (!executable || executable.includes('/') || executable.includes('\\')) {
|
|
493
493
|
continue;
|
|
494
494
|
}
|
|
495
|
+
if (allowedBareExecutables.has(normalizeCommandExecutableName(executable))) {
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
495
498
|
if (!projectLocalBinExecutableExists(projectRoot, executable)) {
|
|
496
499
|
continue;
|
|
497
500
|
}
|
package/dist/core/command-env.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import { readString, readStringArray } from './config-loading.js';
|
|
3
4
|
export const COMMAND_ENV_POLICIES = new Set(['inherit', 'minimal', 'allowlist']);
|
|
@@ -25,6 +26,8 @@ const BASE_MINIMAL_ENV_KEYS = [
|
|
|
25
26
|
'WINDIR',
|
|
26
27
|
'windir',
|
|
27
28
|
];
|
|
29
|
+
export const PROJECT_LOCAL_BIN_BARE_EXECUTABLE_ALLOWLIST_KEY = 'allow_project_local_bin_bare_executables';
|
|
30
|
+
export const DEFAULT_PROJECT_LOCAL_BIN_BARE_EXECUTABLE_ALLOWLIST = new Set(['mf', 'mustflow']);
|
|
28
31
|
function getPathEnvKey(env) {
|
|
29
32
|
return Object.keys(env).find((key) => key.toLowerCase() === 'path') ?? 'PATH';
|
|
30
33
|
}
|
|
@@ -48,6 +51,46 @@ function readEnvPolicy(table) {
|
|
|
48
51
|
function readEnvAllowlist(table) {
|
|
49
52
|
return table ? (readStringArray(table, 'env_allowlist') ?? []) : [];
|
|
50
53
|
}
|
|
54
|
+
export function normalizeCommandExecutableName(executable) {
|
|
55
|
+
return path.basename(executable).replace(/\.(?:cmd|exe|ps1)$/iu, '').toLowerCase();
|
|
56
|
+
}
|
|
57
|
+
export function readProjectLocalBinBareExecutableAllowlist(contractOrCommands) {
|
|
58
|
+
const defaults = contractOrCommands && typeof contractOrCommands === 'object' && 'defaults' in contractOrCommands
|
|
59
|
+
? contractOrCommands.defaults
|
|
60
|
+
: undefined;
|
|
61
|
+
const configuredAllowlist = defaults && typeof defaults === 'object'
|
|
62
|
+
? defaults[PROJECT_LOCAL_BIN_BARE_EXECUTABLE_ALLOWLIST_KEY]
|
|
63
|
+
: undefined;
|
|
64
|
+
if (!Array.isArray(configuredAllowlist)) {
|
|
65
|
+
return DEFAULT_PROJECT_LOCAL_BIN_BARE_EXECUTABLE_ALLOWLIST;
|
|
66
|
+
}
|
|
67
|
+
return new Set(configuredAllowlist
|
|
68
|
+
.filter((entry) => typeof entry === 'string' && entry.trim().length > 0)
|
|
69
|
+
.map((entry) => normalizeCommandExecutableName(entry)));
|
|
70
|
+
}
|
|
71
|
+
export function resolveAllowedProjectLocalBinExecutable(projectRoot, executable, allowlist) {
|
|
72
|
+
if (executable.includes('/') || executable.includes('\\')) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const executableName = normalizeCommandExecutableName(executable);
|
|
76
|
+
if (!allowlist.has(executableName)) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
const localBinPath = path.join(projectRoot, 'node_modules', '.bin');
|
|
80
|
+
const candidates = [
|
|
81
|
+
executableName,
|
|
82
|
+
`${executableName}.cmd`,
|
|
83
|
+
`${executableName}.exe`,
|
|
84
|
+
`${executableName}.ps1`,
|
|
85
|
+
];
|
|
86
|
+
for (const candidate of candidates) {
|
|
87
|
+
const candidatePath = path.join(localBinPath, candidate);
|
|
88
|
+
if (existsSync(candidatePath)) {
|
|
89
|
+
return candidatePath;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
51
94
|
function pickEnv(source, names) {
|
|
52
95
|
const output = {};
|
|
53
96
|
for (const name of names) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { isRecord, readString } from './config-loading.js';
|
|
2
2
|
import { commandIntentBlockedCommandPattern, commandIntentHasCommandSource, commandIntentNameIsSafe, } from './command-contract-rules.js';
|
|
3
|
+
const ALLOW_LONG_RUNNING_COMMAND_PATTERNS_KEY = 'allow_long_running_command_patterns';
|
|
3
4
|
export const COMMAND_INTENT_INELIGIBILITY_CODES = [
|
|
4
5
|
'intent_not_table',
|
|
5
6
|
'status_not_configured',
|
|
@@ -83,7 +84,7 @@ export function evaluateCommandIntentEligibility(intentName, rawIntent) {
|
|
|
83
84
|
detail: blockedPattern.detail,
|
|
84
85
|
};
|
|
85
86
|
}
|
|
86
|
-
if (blockedPattern?.code === 'long_running_command_pattern') {
|
|
87
|
+
if (blockedPattern?.code === 'long_running_command_pattern' && rawIntent[ALLOW_LONG_RUNNING_COMMAND_PATTERNS_KEY] !== true) {
|
|
87
88
|
return {
|
|
88
89
|
ok: false,
|
|
89
90
|
code: 'blocked_long_running_command_pattern',
|
|
@@ -58,6 +58,7 @@ const AGENT_WORKFLOW_PATH = '.mustflow/docs/agent-workflow.md';
|
|
|
58
58
|
const PACKAGE_SCRIPT_RUNNERS = new Set(['bun', 'npm', 'pnpm', 'yarn']);
|
|
59
59
|
const MAKEFILE_CANDIDATES = ['Makefile', 'makefile'];
|
|
60
60
|
const JUSTFILE_CANDIDATES = ['justfile', 'Justfile'];
|
|
61
|
+
const ALLOW_LONG_RUNNING_COMMAND_PATTERNS_KEY = 'allow_long_running_command_patterns';
|
|
61
62
|
function uniqueSorted(values) {
|
|
62
63
|
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
63
64
|
}
|
|
@@ -333,7 +334,7 @@ function lintIntent(name, value, issues) {
|
|
|
333
334
|
if (blockedCommandPattern?.code === 'shell_background_pattern') {
|
|
334
335
|
pushIssue(issues, 'error', 'shell_background_pattern', name, `Shell intent ${name} contains a blocked long-running or background pattern.`);
|
|
335
336
|
}
|
|
336
|
-
if (blockedCommandPattern?.code === 'long_running_command_pattern') {
|
|
337
|
+
if (blockedCommandPattern?.code === 'long_running_command_pattern' && value[ALLOW_LONG_RUNNING_COMMAND_PATTERNS_KEY] !== true) {
|
|
337
338
|
pushIssue(issues, 'error', 'long_running_command_pattern', name, `Intent ${name} contains a blocked long-running or background command pattern.`);
|
|
338
339
|
}
|
|
339
340
|
if (!successExitCodesAreValid(value)) {
|
package/package.json
CHANGED
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"on_timeout": { "type": "string" },
|
|
37
37
|
"kill_after_seconds": { "type": "integer" },
|
|
38
38
|
"env_policy": { "$ref": "#/$defs/envPolicy" },
|
|
39
|
-
"env_allowlist": { "$ref": "#/$defs/stringArray" }
|
|
39
|
+
"env_allowlist": { "$ref": "#/$defs/stringArray" },
|
|
40
|
+
"allow_project_local_bin_bare_executables": { "$ref": "#/$defs/stringArray" }
|
|
40
41
|
}
|
|
41
42
|
},
|
|
42
43
|
"intents": {
|
|
@@ -172,6 +173,7 @@
|
|
|
172
173
|
},
|
|
173
174
|
"cmd": { "type": "string" },
|
|
174
175
|
"allow_shell": { "type": "boolean" },
|
|
176
|
+
"allow_long_running_command_patterns": { "type": "boolean" },
|
|
175
177
|
"cwd": { "type": "string" },
|
|
176
178
|
"timeout_seconds": { "type": "integer" },
|
|
177
179
|
"kill_after_seconds": { "type": "integer" },
|
|
@@ -185,6 +187,7 @@
|
|
|
185
187
|
},
|
|
186
188
|
"env_policy": { "$ref": "#/$defs/envPolicy" },
|
|
187
189
|
"env_allowlist": { "$ref": "#/$defs/stringArray" },
|
|
190
|
+
"allow_env_inheritance_risks": { "type": "boolean" },
|
|
188
191
|
"manual_start_hint": { "type": "string" },
|
|
189
192
|
"health_check_url": { "type": "string" },
|
|
190
193
|
"stop_instruction": { "type": "string" },
|
|
@@ -18,6 +18,7 @@ on_timeout = "terminate_process_tree"
|
|
|
18
18
|
kill_after_seconds = 5
|
|
19
19
|
env_policy = "minimal"
|
|
20
20
|
env_allowlist = []
|
|
21
|
+
allow_project_local_bin_bare_executables = ["mf", "mustflow"]
|
|
21
22
|
|
|
22
23
|
[resources.local_index_cache]
|
|
23
24
|
description = "Generated mustflow SQLite local index under .mustflow/cache/."
|
|
@@ -56,7 +56,7 @@ translations = {}
|
|
|
56
56
|
[documents."skills.index"]
|
|
57
57
|
source = "locales/en/.mustflow/skills/INDEX.md"
|
|
58
58
|
source_locale = "en"
|
|
59
|
-
revision =
|
|
59
|
+
revision = 89
|
|
60
60
|
translations = {}
|
|
61
61
|
|
|
62
62
|
[documents."skill.adapter-boundary"]
|
|
@@ -209,6 +209,12 @@ source_locale = "en"
|
|
|
209
209
|
revision = 2
|
|
210
210
|
translations = {}
|
|
211
211
|
|
|
212
|
+
[documents."skill.docker-code-change"]
|
|
213
|
+
source = "locales/en/.mustflow/skills/docker-code-change/SKILL.md"
|
|
214
|
+
source_locale = "en"
|
|
215
|
+
revision = 1
|
|
216
|
+
translations = {}
|
|
217
|
+
|
|
212
218
|
[documents."skill.elysia-code-change"]
|
|
213
219
|
source = "locales/en/.mustflow/skills/elysia-code-change/SKILL.md"
|
|
214
220
|
source_locale = "en"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
mustflow_doc: skills.index
|
|
3
3
|
locale: en
|
|
4
4
|
canonical: true
|
|
5
|
-
revision:
|
|
5
|
+
revision: 89
|
|
6
6
|
authority: router
|
|
7
7
|
lifecycle: mustflow-owned
|
|
8
8
|
---
|
|
@@ -103,6 +103,7 @@ routes. Event routes stay inactive until their event occurs.
|
|
|
103
103
|
| C++ source, headers, modules, native build metadata, toolchains, package managers, public headers, shared or static libraries, ABI surfaces, generated bindings, FFI, tests, or benchmarks are created or changed | `.mustflow/skills/cpp-code-change/SKILL.md` | Owning target, compilation identity, build front door, changed consumed surface, public API/ABI/FFI/binding surfaces, ownership and lifetime contracts, and command contract entries | C++ source, headers, modules, build metadata, package metadata, generated bindings, FFI code, tests, benchmarks, and directly synchronized docs | target drift, source API break, binary ABI break, undefined behavior, lifetime bug, build-graph drift, generated-binding drift, FFI memory bug, unverified modern C++ feature, or false performance claim | `changes_status`, `changes_diff_summary`, `lint`, `build`, `test_related`, `test`, `docs_validate_fast`, `test_release`, `mustflow_check` | Owning target, compilation identity, highest compatibility risk, ownership/lifetime/UB/concurrency notes, public API/ABI/FFI/binding impact, verification, and remaining C++ risk |
|
|
104
104
|
| Node.js runtime code, package manager ownership, module format, package entry metadata, native dependencies, Node test runner behavior, TypeScript execution mode, or deployment runtime support is created or changed | `.mustflow/skills/node-code-change/SKILL.md` | Node version signals, package manager and lockfile owner, module/package metadata, TypeScript loader, test runner, native dependency, deployment target, and command contract entries | Node runtime code, package metadata, lockfiles, scripts, CI or Docker runtime declarations, test runner config, native dependency handling, docs examples, and directly synchronized package surfaces | newest-Node assumption, package manager drift, ESM/CJS break, blocked deep import, native dependency break, Node native TypeScript overclaim, test runner migration risk, deployment mismatch, or permission-model overclaim | `changes_status`, `changes_diff_summary`, `lint`, `build`, `test_related`, `test`, `docs_validate_fast`, `test_release`, `mustflow_check` | Runtime and package manager decision, module/package entry notes, TypeScript/test runner notes, native/deployment risks, verification, and remaining Node.js risk |
|
|
105
105
|
| Bun runtime code, Bun package manager behavior, `bun.lock`, `bunfig.toml`, Bun test runner behavior, Bun bundling, Bun TypeScript execution, or Bun-specific APIs are created or changed | `.mustflow/skills/bun-code-change/SKILL.md` | Bun role signals, `package.json`, Bun and non-Bun lockfiles, `bunfig.toml`, CI/Docker Bun setup, TypeScript config, Bun APIs, native dependency signals, and command contract entries | Bun runtime code, Bun package manager metadata, lockfiles, `bunfig.toml`, scripts, tests, bundler config, TypeScript/declaration pipeline, package metadata, and directly synchronized docs | Bun role confusion, lockfile drift, trusted dependency overgrant, runtime/package-manager conflation, Bun TypeScript typecheck overclaim, Bun build declaration gap, Node compatibility break, shebang mismatch, or native binary break | `changes_status`, `changes_diff_summary`, `lint`, `build`, `test_related`, `test`, `docs_validate_fast`, `test_release`, `mustflow_check` | Bun role classification, lockfile/trust notes, runtime/type/build/test notes, Node compatibility risks, verification, and remaining Bun risk |
|
|
106
|
+
| Dockerfiles, `.dockerignore`, Docker Compose files, BuildKit or buildx behavior, container image metadata, tags, entrypoints, health checks, Docker CI workflows, image security scanning, SBOM or provenance settings, registry publishing, or container runtime validation are created or changed | `.mustflow/skills/docker-code-change/SKILL.md` | Docker surfaces, project image shape, base image and platform signals, build context and cache signals, runtime contract, security and supply-chain contract, and command contract entries | Dockerfiles, `.dockerignore`, Compose files, container CI workflow snippets, image metadata, package tests, docs examples, template metadata, and directly synchronized skill routes | cache breakage, secret leak, root runtime, host access escape, dev dependency in final image, mutable tag drift, untrusted CI publish, missing SBOM/provenance, unverified runtime, or false production-readiness claim | `changes_status`, `changes_diff_summary`, `lint`, `build`, `test_related`, `test`, `docs_validate_fast`, `test_release`, `mustflow_check` | Docker surface classification, image/base/cache/stage decisions, secret/user/runtime/Compose/CI supply-chain notes, verification, and remaining Docker risk |
|
|
106
107
|
| TypeScript source, declarations, tsconfig, package exports, module resolution, public API, or TypeScript tests are created or changed | `.mustflow/skills/typescript-code-change/SKILL.md` | TypeScript config, package entry metadata, target runtime, changed files, and command contract entries | TypeScript source, declarations, compiler config, exports, tests, and directly synchronized docs | weakened type safety, module drift, public API drift, or unverified declaration output | `changes_status`, `changes_diff_summary`, `lint`, `build`, `test_related`, `test`, `docs_validate_fast`, `mustflow_check` | Runtime, module, type, and public API boundary checked, changes made, verification, and remaining TypeScript risk |
|
|
107
108
|
| JavaScript source, module format, package entry, browser or Node runtime, dependency usage, Promise handling, bundler config, or JavaScript tests are created or changed | `.mustflow/skills/javascript-code-change/SKILL.md` | Package metadata, module system, runtime target, entrypoints, changed files, and command contract entries | JavaScript source, package exports, bundler config, dependencies, tests, and docs examples | runtime API leakage, ESM/CJS drift, discarded Promise, dependency bloat, or broken package entry | `changes_status`, `changes_diff_summary`, `lint`, `build`, `test_related`, `test`, `docs_validate_fast`, `mustflow_check` | Runtime and module boundary checked, async and dependency notes, verification, and remaining JavaScript risk |
|
|
108
109
|
| Python source, package metadata, runtime version, import layout, type checking, linting, CLI entry points, or tests are created or changed | `.mustflow/skills/python-code-change/SKILL.md` | Python version source, packaging files, import layout, lint/type/test config, changed files, and command contract entries | Python source, packaging metadata, imports, type hints, tests, and docs examples | unsupported syntax, import hacks, packaging drift, swallowed errors, or weakened lint/type checks | `changes_status`, `changes_diff_summary`, `lint`, `build`, `test_related`, `test`, `docs_validate_fast`, `mustflow_check` | Runtime, packaging, import, and type boundary checked, verification, and remaining Python risk |
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
---
|
|
2
|
+
mustflow_doc: skill.docker-code-change
|
|
3
|
+
locale: en
|
|
4
|
+
canonical: true
|
|
5
|
+
revision: 1
|
|
6
|
+
lifecycle: mustflow-owned
|
|
7
|
+
authority: procedure
|
|
8
|
+
name: docker-code-change
|
|
9
|
+
description: Apply this skill when Dockerfiles, .dockerignore files, Docker Compose files, BuildKit or buildx behavior, container image metadata, image tags, container entrypoints, health checks, Docker-based CI workflows, image security scanning, SBOM or provenance settings, registry publishing, or container runtime validation are created or changed.
|
|
10
|
+
metadata:
|
|
11
|
+
mustflow_schema: "1"
|
|
12
|
+
mustflow_kind: procedure
|
|
13
|
+
pack_id: mustflow.core
|
|
14
|
+
skill_id: mustflow.core.docker-code-change
|
|
15
|
+
command_intents:
|
|
16
|
+
- changes_status
|
|
17
|
+
- changes_diff_summary
|
|
18
|
+
- lint
|
|
19
|
+
- build
|
|
20
|
+
- test_related
|
|
21
|
+
- test
|
|
22
|
+
- docs_validate_fast
|
|
23
|
+
- test_release
|
|
24
|
+
- mustflow_check
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# Docker Code Change
|
|
28
|
+
|
|
29
|
+
<!-- mustflow-section: purpose -->
|
|
30
|
+
## Purpose
|
|
31
|
+
|
|
32
|
+
Prevent container image accidents by preserving reproducibility, secret safety, cache behavior,
|
|
33
|
+
runtime correctness, development and production separation, and supply-chain evidence.
|
|
34
|
+
|
|
35
|
+
This skill is not a Docker syntax guide. It is a safety procedure for changing Docker-based
|
|
36
|
+
application images and local container workflows without silently weakening build, runtime, CI,
|
|
37
|
+
or security contracts.
|
|
38
|
+
|
|
39
|
+
<!-- mustflow-section: use-when -->
|
|
40
|
+
## Use When
|
|
41
|
+
|
|
42
|
+
- `Dockerfile`, `Dockerfile.*`, `.dockerignore`, `compose.yaml`, `compose.yml`,
|
|
43
|
+
`docker-compose*.yml`, or Compose override files are created or changed.
|
|
44
|
+
- Base images, image tags, digest pinning, package-manager install layers, build contexts,
|
|
45
|
+
multi-stage boundaries, `ENTRYPOINT`, `CMD`, `USER`, `HEALTHCHECK`, `EXPOSE`, labels,
|
|
46
|
+
environment variables, or build arguments change.
|
|
47
|
+
- BuildKit, buildx, build targets, cache mounts, external cache, multi-platform image builds,
|
|
48
|
+
Docker-based CI workflows, image publish behavior, registry tags, SBOM, provenance,
|
|
49
|
+
signing, or image vulnerability scanning changes.
|
|
50
|
+
- Local development Compose services such as databases, Redis, queues, object stores,
|
|
51
|
+
mail capture, optional debug tools, profiles, volumes, networks, env files, init scripts,
|
|
52
|
+
or migration jobs change.
|
|
53
|
+
- A language-specific runtime skill mentions Docker base images, native dependency image
|
|
54
|
+
behavior, container deployment support, or Docker runtime declarations.
|
|
55
|
+
|
|
56
|
+
<!-- mustflow-section: do-not-use-when -->
|
|
57
|
+
## Do Not Use When
|
|
58
|
+
|
|
59
|
+
- The task only changes application code that happens to run inside an unchanged container;
|
|
60
|
+
use the matching language or framework skill.
|
|
61
|
+
- The task only changes generic environment variables, secrets, or deployment settings
|
|
62
|
+
outside Docker or Compose; use `config-env-change` or the narrower deployment skill.
|
|
63
|
+
- The task designs Kubernetes, ECS, Cloud Run, Nomad, service mesh, registry administration,
|
|
64
|
+
autoscaling, backup, ingress, TLS, or cloud platform resources beyond verifying that an
|
|
65
|
+
image is deployable.
|
|
66
|
+
- The task only addresses shell process execution or filesystem path handling outside
|
|
67
|
+
container files; use `process-execution-safety`, `file-path-cross-platform-change`, or
|
|
68
|
+
`cross-platform-filesystem-safety`.
|
|
69
|
+
|
|
70
|
+
<!-- mustflow-section: required-inputs -->
|
|
71
|
+
## Required Inputs
|
|
72
|
+
|
|
73
|
+
- Container surfaces: Dockerfiles, `.dockerignore`, Compose files, CI workflow files,
|
|
74
|
+
build scripts or command-contract entries, release workflow files, and registry metadata
|
|
75
|
+
touched by the change.
|
|
76
|
+
- Project classification: runtime-source app, compiled artifact app, JVM artifact app,
|
|
77
|
+
static frontend, multi-service app, or mixed image set, with language examples such as
|
|
78
|
+
Node, Bun, Python, PHP, Go, Rust, C++, and Java.
|
|
79
|
+
- Base image and platform signals: image names, tags, digests, OS family, libc expectations,
|
|
80
|
+
CPU architecture, native dependencies, required CA certificates, time zone, shell, package
|
|
81
|
+
manager, and runtime user needs.
|
|
82
|
+
- Build and cache signals: build context, `.dockerignore`, lockfiles, package-manager cache
|
|
83
|
+
paths, BuildKit mount needs, stage names, build targets, external cache ownership, and
|
|
84
|
+
CI event or branch conditions.
|
|
85
|
+
- Runtime contract: `USER`, file ownership, writable paths, `ENTRYPOINT`, `CMD`, signal
|
|
86
|
+
handling, health checks, ports, logs, config injection, read-only filesystem expectations,
|
|
87
|
+
volumes, and smoke-test path.
|
|
88
|
+
- Security and supply-chain contract: secrets, SSH keys, private registry tokens, Docker socket
|
|
89
|
+
access, privileged mode, host namespace or host path access, capabilities, security options,
|
|
90
|
+
vulnerability scan gate, SBOM, provenance, signing, and digest reporting.
|
|
91
|
+
- Configured command intents that can validate syntax, build output, tests, docs, release
|
|
92
|
+
packaging, and mustflow workflow alignment. Report missing Docker-specific verification
|
|
93
|
+
intents instead of inventing raw Docker commands.
|
|
94
|
+
|
|
95
|
+
<!-- mustflow-section: preconditions -->
|
|
96
|
+
## Preconditions
|
|
97
|
+
|
|
98
|
+
- Classify whether the change affects local development only, CI validation, release images,
|
|
99
|
+
registry publishing, or deployable runtime behavior before editing.
|
|
100
|
+
- Do not optimize a Dockerfile by blindly minimizing line count or image size. Preserve
|
|
101
|
+
reproducibility, secret safety, cache behavior, runtime correctness, and dev/prod separation
|
|
102
|
+
first.
|
|
103
|
+
- Treat Dockerfiles, Compose files, and Docker CI workflows as security-sensitive when they
|
|
104
|
+
can alter credentials, registry writes, host access, runtime privileges, or supply-chain
|
|
105
|
+
attestations.
|
|
106
|
+
- Do not assume Docker, buildx, Compose, Scout, Trivy, Grype, or registry credentials are
|
|
107
|
+
available unless the repository exposes a configured one-shot command intent or the user
|
|
108
|
+
explicitly accepts an unverified manual path.
|
|
109
|
+
|
|
110
|
+
<!-- mustflow-section: allowed-edits -->
|
|
111
|
+
## Allowed Edits
|
|
112
|
+
|
|
113
|
+
- Update Dockerfiles, `.dockerignore`, Compose files, container-related CI workflow snippets,
|
|
114
|
+
image metadata, package tests, docs examples, template metadata, and directly synchronized
|
|
115
|
+
skill routes required by the container contract.
|
|
116
|
+
- Add or tighten non-root runtime users, stage names, `.dockerignore` exclusions, cache-safe
|
|
117
|
+
copy order, BuildKit secret or cache requirements, health checks, labels, and Compose local
|
|
118
|
+
dependency wiring when the current project evidence supports the change.
|
|
119
|
+
- Add focused tests or assertions only when they encode the changed container, template,
|
|
120
|
+
package, or workflow contract.
|
|
121
|
+
- Do not add broad deployment platform design, registry administration, long-running server
|
|
122
|
+
instructions, raw publish commands, credential material, or command permission to a skill
|
|
123
|
+
document.
|
|
124
|
+
|
|
125
|
+
<!-- mustflow-section: procedure -->
|
|
126
|
+
## Procedure
|
|
127
|
+
|
|
128
|
+
1. Classify the changed surface: Dockerfile, `.dockerignore`, Compose, CI build workflow,
|
|
129
|
+
image publish workflow, image metadata, security scan, SBOM/provenance, or runtime smoke
|
|
130
|
+
path. If several surfaces changed, name the source of truth for each.
|
|
131
|
+
2. Classify the image shape before choosing structure:
|
|
132
|
+
- Runtime-source apps keep source plus production runtime dependencies.
|
|
133
|
+
- Compiled artifact apps should usually copy only the binary and required runtime files.
|
|
134
|
+
- JVM artifact apps should build with a JDK and run with a JRE or equivalent runtime image.
|
|
135
|
+
- Static frontends should copy only built assets into the serving image when applicable.
|
|
136
|
+
3. Choose base images deliberately. Prefer trusted versioned images over mutable `latest`.
|
|
137
|
+
Use Debian slim as a conservative default for native dependency compatibility; use Alpine
|
|
138
|
+
only after libc and native package behavior are verified; use distroless or `scratch` only
|
|
139
|
+
when CA certificates, time zone, passwd or non-root identity, shell absence, and debugging
|
|
140
|
+
tradeoffs are explicit.
|
|
141
|
+
4. Treat digest pinning as a reproducibility choice with an update obligation. If a production
|
|
142
|
+
sample pins a digest, also report the need for an update mechanism such as dependency update
|
|
143
|
+
automation, base-image rebuild checks, or a scanner policy.
|
|
144
|
+
5. Preserve build cache boundaries. Keep build context small, copy dependency manifests and
|
|
145
|
+
lockfiles before application source, avoid copying host dependency directories, and keep
|
|
146
|
+
package-manager caches out of final images. Do not move `COPY . .` above dependency install
|
|
147
|
+
layers unless the project has no cache-sensitive dependency step.
|
|
148
|
+
6. Check `.dockerignore` whenever build context changes. Exclude VCS metadata, local dependency
|
|
149
|
+
directories, virtual environments, build output, coverage, caches, local databases, `.env`,
|
|
150
|
+
credential files, keys, and other files not required by the build.
|
|
151
|
+
7. Use multi-stage boundaries only when they buy cache, artifact, security, or test-target value.
|
|
152
|
+
Name stages instead of relying on numeric indexes. Remove stages that merely rename the same
|
|
153
|
+
base without changing cache behavior, artifact flow, runtime base, or verification target.
|
|
154
|
+
8. Ensure final images contain only runtime requirements. Do not leave compilers, package managers,
|
|
155
|
+
test fixtures, source maps, caches, `git`, `curl`, shell tools, or dev dependencies in final
|
|
156
|
+
images unless the runtime contract explicitly requires them.
|
|
157
|
+
9. Handle secrets as a hard boundary. Do not put tokens, passwords, SSH keys, cloud credentials,
|
|
158
|
+
`.npmrc`, `.pypirc`, `.env`, or private registry credentials into `ARG`, `ENV`, labels,
|
|
159
|
+
image layers, build logs, copied files, or command history. Prefer BuildKit secret or SSH
|
|
160
|
+
mounts when a configured workflow supports them, and report missing secret-mount verification
|
|
161
|
+
when it does not.
|
|
162
|
+
10. Preserve runtime correctness. Verify non-root user intent, file ownership, writable paths,
|
|
163
|
+
entrypoint and command shape, PID 1 signal handling, exposed and published ports, logs to
|
|
164
|
+
stdout or stderr, health check command availability, required environment variables, and
|
|
165
|
+
read-only filesystem expectations.
|
|
166
|
+
11. Treat `USER` as a runtime proof obligation, not a text check. If the final image runs as
|
|
167
|
+
non-root, make sure copied files and runtime write paths are owned or writable by that user.
|
|
168
|
+
If that cannot be verified, report the missing run evidence.
|
|
169
|
+
12. Keep Compose scoped. Use Compose for local development, integration tests, and narrow
|
|
170
|
+
production-like checks. Do not turn Compose into a full orchestrator design for TLS,
|
|
171
|
+
autoscaling, backups, ingress, secret rotation, or platform rollout strategy.
|
|
172
|
+
13. For Compose dependencies, distinguish container start from service readiness. Prefer
|
|
173
|
+
health checks for databases and queues, app-level retry for runtime dependency loss, named
|
|
174
|
+
volumes for persistent local data, bind mounts for editable source, profiles for optional
|
|
175
|
+
tools, and one-shot migration services rather than hiding app migrations inside database
|
|
176
|
+
image entrypoints.
|
|
177
|
+
14. Review Compose trust and host access. Treat `privileged`, Docker socket mounts, host
|
|
178
|
+
networking, host PID or IPC namespaces, broad host-path mounts, root users, broad port
|
|
179
|
+
binding, unconfined security profiles, and missing resource limits as high-risk changes
|
|
180
|
+
requiring explicit justification.
|
|
181
|
+
15. For CI, separate test builds from publish builds. PR and fork events should not push images,
|
|
182
|
+
receive registry credentials, write production caches, sign artifacts, or use deployment
|
|
183
|
+
secrets. Release tags or protected default-branch jobs may publish only after the configured
|
|
184
|
+
verification path succeeds.
|
|
185
|
+
16. Keep cache ownership safe in CI. Do not let untrusted PRs overwrite default-branch cache
|
|
186
|
+
refs. Use branch- or event-scoped cache references when the workflow supports external cache.
|
|
187
|
+
Report cache poisoning risk when the workflow writes shared caches from untrusted code.
|
|
188
|
+
17. Keep image tags traceable. Use immutable commit or digest evidence for deployable artifacts.
|
|
189
|
+
Treat `latest` as a moving pointer, not a release identity. Release workflows should record
|
|
190
|
+
the pushed digest and update floating tags only from release or protected branch events.
|
|
191
|
+
18. For release images, require SBOM and provenance when the configured workflow supports them.
|
|
192
|
+
Report when local-only image loads cannot carry registry attestations and when final published
|
|
193
|
+
digests were not rechecked after push.
|
|
194
|
+
19. Choose verification through configured intents first. If Docker-specific syntax, build,
|
|
195
|
+
smoke, inspect, history, vulnerability scan, SBOM, provenance, multi-arch, or registry-pull
|
|
196
|
+
verification is needed but not configured, report the missing intent instead of running an
|
|
197
|
+
inferred command.
|
|
198
|
+
20. When reporting completion, separate source edits, image-build evidence, runtime evidence,
|
|
199
|
+
security scan evidence, supply-chain evidence, registry evidence, and skipped checks. Do not
|
|
200
|
+
claim a container image is production-ready from source inspection or a successful build alone.
|
|
201
|
+
|
|
202
|
+
<!-- mustflow-section: postconditions -->
|
|
203
|
+
## Postconditions
|
|
204
|
+
|
|
205
|
+
- The image shape, base image choice, cache order, stage boundaries, and build context are
|
|
206
|
+
deliberate and aligned with the language or runtime contract.
|
|
207
|
+
- Secrets are not introduced into Dockerfile instructions, Compose environment, image layers,
|
|
208
|
+
command history, logs, SBOM, or provenance metadata.
|
|
209
|
+
- Final runtime images avoid root execution and unnecessary build tools unless explicitly justified.
|
|
210
|
+
- Compose remains local or narrowly production-like, with host access and privileged settings
|
|
211
|
+
justified or rejected.
|
|
212
|
+
- CI image builds separate test, cache, publish, tag, SBOM, provenance, and registry credentials
|
|
213
|
+
according to event trust.
|
|
214
|
+
- Docker-specific verification evidence is recorded, or missing configured intents are reported.
|
|
215
|
+
|
|
216
|
+
<!-- mustflow-section: verification -->
|
|
217
|
+
## Verification
|
|
218
|
+
|
|
219
|
+
Use configured oneshot command intents when available:
|
|
220
|
+
|
|
221
|
+
- `lint`
|
|
222
|
+
- `build`
|
|
223
|
+
- `test_related`
|
|
224
|
+
- `test`
|
|
225
|
+
- `docs_validate_fast`
|
|
226
|
+
- `test_release`
|
|
227
|
+
- `mustflow_check`
|
|
228
|
+
|
|
229
|
+
Report missing Dockerfile lint, Compose config validation, buildx check, image build, container
|
|
230
|
+
start, health or smoke test, image inspect, history secret scan, vulnerability scan, SBOM,
|
|
231
|
+
provenance, multi-platform manifest, registry push, registry pull, or digest verification intents
|
|
232
|
+
when those surfaces change.
|
|
233
|
+
|
|
234
|
+
<!-- mustflow-section: failure-handling -->
|
|
235
|
+
## Failure Handling
|
|
236
|
+
|
|
237
|
+
- If a build succeeds but runtime start, health, smoke, or non-root write behavior is unverified,
|
|
238
|
+
report the image as built but not runtime-verified.
|
|
239
|
+
- If a secret appears in `ARG`, `ENV`, copied files, image history, logs, or attestation metadata,
|
|
240
|
+
remove the leak path before optimizing cache or image size.
|
|
241
|
+
- If Alpine, distroless, or `scratch` breaks native dependencies, CA certificates, time zones,
|
|
242
|
+
shell availability, or non-root identity, restore a compatible runtime base or report the
|
|
243
|
+
missing runtime requirement.
|
|
244
|
+
- If Compose uses Docker socket, privileged mode, host namespaces, broad host mounts, root users,
|
|
245
|
+
or broad port exposure without explicit justification, treat the change as unsafe.
|
|
246
|
+
- If CI publish behavior is triggered from untrusted events, forks, or ordinary PRs, fail closed
|
|
247
|
+
by disabling push or credentials for that path and report the publish boundary.
|
|
248
|
+
- If Docker-specific tools or registries are unavailable under the command contract, do not invent
|
|
249
|
+
manual commands; report the missing verification intent and remaining risk.
|
|
250
|
+
|
|
251
|
+
<!-- mustflow-section: output-format -->
|
|
252
|
+
## Output Format
|
|
253
|
+
|
|
254
|
+
- Docker surface classification
|
|
255
|
+
- Image shape, base image, cache, and stage decisions
|
|
256
|
+
- `.dockerignore`, secret, user, entrypoint, health, port, and runtime notes
|
|
257
|
+
- Compose trust, volume, network, env, readiness, and migration notes
|
|
258
|
+
- CI cache, tag, publish, SBOM, provenance, registry, and event-trust notes
|
|
259
|
+
- Files changed
|
|
260
|
+
- Command intents run
|
|
261
|
+
- Skipped Docker-specific checks and reasons
|
|
262
|
+
- Remaining Docker risk
|
|
@@ -132,6 +132,12 @@ route_type = "primary"
|
|
|
132
132
|
priority = 85
|
|
133
133
|
applies_to_reasons = ["code_change", "public_api_change", "test_change", "package_metadata_change"]
|
|
134
134
|
|
|
135
|
+
[routes."docker-code-change"]
|
|
136
|
+
category = "general_code"
|
|
137
|
+
route_type = "primary"
|
|
138
|
+
priority = 85
|
|
139
|
+
applies_to_reasons = ["code_change", "public_api_change", "test_change", "security_change", "package_metadata_change", "release_risk"]
|
|
140
|
+
|
|
135
141
|
[routes."api-contract-change"]
|
|
136
142
|
category = "general_code"
|
|
137
143
|
route_type = "primary"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
id = "default"
|
|
2
2
|
name = "default"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.28.0"
|
|
4
4
|
description = "Minimal workflow for LLM agents to read, edit, and verify their work in a repository."
|
|
5
5
|
common_root = "common"
|
|
6
6
|
locales_root = "locales"
|
|
@@ -25,6 +25,7 @@ creates = [
|
|
|
25
25
|
".mustflow/skills/css-code-change/SKILL.md",
|
|
26
26
|
".mustflow/skills/cpp-code-change/SKILL.md",
|
|
27
27
|
".mustflow/skills/dart-code-change/SKILL.md",
|
|
28
|
+
".mustflow/skills/docker-code-change/SKILL.md",
|
|
28
29
|
".mustflow/skills/elysia-code-change/SKILL.md",
|
|
29
30
|
".mustflow/skills/flutter-code-change/SKILL.md",
|
|
30
31
|
".mustflow/skills/go-code-change/SKILL.md",
|
|
@@ -135,6 +136,7 @@ minimal = [
|
|
|
135
136
|
"css-code-change",
|
|
136
137
|
"cpp-code-change",
|
|
137
138
|
"dart-code-change",
|
|
139
|
+
"docker-code-change",
|
|
138
140
|
"elysia-code-change",
|
|
139
141
|
"flutter-code-change",
|
|
140
142
|
"go-code-change",
|
|
@@ -190,6 +192,7 @@ patterns = [
|
|
|
190
192
|
"css-code-change",
|
|
191
193
|
"cpp-code-change",
|
|
192
194
|
"dart-code-change",
|
|
195
|
+
"docker-code-change",
|
|
193
196
|
"elysia-code-change",
|
|
194
197
|
"flutter-code-change",
|
|
195
198
|
"go-code-change",
|
|
@@ -256,6 +259,7 @@ oss = [
|
|
|
256
259
|
"css-code-change",
|
|
257
260
|
"cpp-code-change",
|
|
258
261
|
"dart-code-change",
|
|
262
|
+
"docker-code-change",
|
|
259
263
|
"elysia-code-change",
|
|
260
264
|
"flutter-code-change",
|
|
261
265
|
"go-code-change",
|
|
@@ -335,6 +339,7 @@ team = [
|
|
|
335
339
|
"css-code-change",
|
|
336
340
|
"cpp-code-change",
|
|
337
341
|
"dart-code-change",
|
|
342
|
+
"docker-code-change",
|
|
338
343
|
"elysia-code-change",
|
|
339
344
|
"flutter-code-change",
|
|
340
345
|
"go-code-change",
|
|
@@ -402,6 +407,7 @@ product = [
|
|
|
402
407
|
"css-code-change",
|
|
403
408
|
"cpp-code-change",
|
|
404
409
|
"dart-code-change",
|
|
410
|
+
"docker-code-change",
|
|
405
411
|
"elysia-code-change",
|
|
406
412
|
"flutter-code-change",
|
|
407
413
|
"go-code-change",
|
|
@@ -474,6 +480,7 @@ library = [
|
|
|
474
480
|
"css-code-change",
|
|
475
481
|
"cpp-code-change",
|
|
476
482
|
"dart-code-change",
|
|
483
|
+
"docker-code-change",
|
|
477
484
|
"elysia-code-change",
|
|
478
485
|
"flutter-code-change",
|
|
479
486
|
"go-code-change",
|