[bug fix] Harden project installation with manifests and portable checks - #351
jarmo-blip wants to merge 3 commits into
Conversation
DeepSeek reviewReviewed the installer-only implementation through cc-code with the explicit router alias No remaining identified P1/P2 findings. Findings addressed before publication:
The colon-space backup parsing suspicion was dismissed after checking the real code and reproducing Non-blocking maintainability suggestion: repeated argument guards are retained beside each option for clarity. Generated-index description reuse is explicitly limited to supported plain Validation: 37/37 functional tests, ShellCheck and whitespace checks pass locally. Exact-head CI passes on Linux Bash 5.2.21 and macOS system Bash 3.2.57, including ShellCheck and all 37 tests on each. Mandatory diff-scoped repo-auditor |
There was a problem hiding this comment.
💡 Codex Review
https://github.com/buildermethods/agent-os/blob/273c85d4cc0fc14d4188e59e0887a2f1134ab13d/scripts/project-project-install.sh#L339-L343
Preserve descriptions for non-alphanumeric index keys
On a subsequent forced install after /index-standards has supplied custom descriptions, this parser recognizes only unquoted folder and standard keys containing [A-Za-z0-9_./-]. Keys with spaces, colons, hashes, reserved words, or numeric prefixes are emitted by this installer either as valid plain scalars or quoted scalars, but are not read back here, so their curated descriptions are silently replaced with the default placeholder.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if [ "$first" -eq 1 ]; then | ||
| ico_die "empty manifest (missing header): $file" | ||
| fi |
There was a problem hiding this comment.
Reject manifests with no managed rows
When a manifest has the correct header but no data rows—for example, after truncation at a newline boundary—first is cleared and validation succeeds. Consequently, doctor.sh exits successfully with “all 0 managed file(s) match” even if installed files remain, and uninstall.sh removes the manifest while leaving those files behind. Track whether at least one valid data row was read and reject a header-only manifest.
Useful? React with 👍 / 👎.
DeepSeek review — follow-up implementationDeepSeek reviewed the follow-up diff at The review found no remaining P1/P2 findings. The follow-up preserves descriptions for quoted and escaped standard-index keys and now fails closed before project mutation for duplicate folder/name keys, missing descriptions, unsupported YAML indicators, and tab/carriage-return corruption. The literal Bash lookup also preserves backslashes on Bash 3.2/macOS awk paths. Validation:
The PR remains installer-hardening-only. No adapters, router, optimizer, release workflow, or credentials are included. |
Summary
The current installer searches
profiles/<name>/standardseven though the default profile is flat, so a default installation omitsglobal/tech-stack.md. It also writes directly into project files without tracking ownership or protecting local edits.This is the installer-hardening-only replacement requested in the review of #348. It installs flat profiles with inheritance, preserves supplied
index.ymlbytes and metadata, stages writes, commits files by atomic sibling rename with rollback, and records SHA-256 ownership in a validated project-relative manifest. Unmanaged or modified destinations require--force, which creates a unique backup. Doctor reports drift; uninstall removes only tracked files and preserves user changes unless explicitly forced.The command destination remains
.claude/commands/agent-os;--target noneinstalls standards only. There is no generated Codex skill adapter, LLM router/optimizer, release preparation, command-content rewrite, or profile-schema migration in this PR. Existing profile indexes are opaque inputs; curated-skill installation remains a separate integration.Linked item
Follow-up to the requested-changes review on #348: #348 (review)
Checklist
docs/installer.mdDocumented steps to test
bash tests/installer.sh.shellcheck -x scripts/installer-common.sh scripts/project-install.sh scripts/doctor.sh scripts/uninstall.sh tests/installer.sh./bin/bash tests/installer.sh; the harness invokes every installer script with the same interpreter.scripts/project-install.sh --project-dir <dir> --yes, edit a tracked standard, and verify doctor fails and an unforced reinstall preserves the edit. Forced reinstall must preserve a backup.Notes for reviewers
Validated head:
b844c9399c518abd856ebc27a68ebd0be79691f2, based on upstreammainat475b0cac4c7c5cf2336ad5a663b691a6d3415e05.git diff --checkpass.main: no critical/high findings. Final diff-scoped--base <upstream SHA> --strict --sarifaudit: 0 findings in the 7 changed files, gate passed. Semgrep/Gitleaks ran, target-code execution and LLM interpretation were disabled; the separate model review ran through cc-code.deepseek:deepseek-chat: no remaining P1/P2 after fixes, including duplicate/malformed index structures and portable Bash 3.2/BSD awk behavior.The workflow runs ShellCheck and functional tests on Linux and macOS. Hashing supports GNU
sha256sum, macOSshasum, andopensslwithoutrealpath -m.The manifest preserves ownership of previously installed files when they disappear from a newer profile or when only commands/standards are updated. Uninstall never recursively removes directories or follows symlink components.