aim/.plans/012-security-hardening-config-and-integrity/2026-03-21-security-hardening-config-and-integrity-implementation-plan.md

391 lines
No EOL
13 KiB
Markdown

# Security Hardening Config And Integrity Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Add secure-by-default HTTP policy controls, enforce AppImageHub HTTPS and checksum handling, sanitize desktop entries, harden stable-ID path usage, and document the remaining AppImageHub trust issue.
**Architecture:** Extend the existing runtime `CliConfig` with `allow_http`, thread that config into dispatch and add/install planning, keep provider-returned AppImageHub URLs on a stricter HTTPS-only path, add a provider-specific MD5 integrity check distinct from the existing trusted checksum mechanism, and tighten install-time path and desktop-entry generation at the boundary where files are written.
**Tech Stack:** Rust workspace, Cargo tests, TOML config loading, existing install pipeline, fixture-backed provider tests.
---
### Task 1: Record the approved security shape in repo docs
**Files:**
- Create: `.architecture/security-issues.md`
- Modify: `README.md`
- Reference: `.audits/2026-03-21T20-08-04Z-post-appimagehub-security-audit.md`
**Step 1: Write the security issues note**
Create `.architecture/security-issues.md` with:
- a short description of the AppImageHub host-trust gap
- current mitigation: AppImageHub downloads must be HTTPS
- deferred work: domain allowlist / provider trust policy
- status label such as `open`
**Step 2: Update the README security/config section**
Document:
- `allow_http = false` default
- `allow_http = true` only affects user-supplied HTTP sources
- provider-returned AppImageHub URLs remain HTTPS-only
**Step 3: Verify docs exist and read clearly**
Run: `rg -n "allow_http|AppImageHub|security" README.md .architecture/security-issues.md`
Expected: matching lines in both files
**Step 4: Commit**
```bash
git add .architecture/security-issues.md README.md
git commit -m "docs: record download security policy"
```
### Task 2: Add `allow_http` to runtime config and thread it into dispatch
**Files:**
- Modify: `crates/aim-cli/src/config.rs`
- Modify: `crates/aim-cli/src/main.rs`
- Modify: `crates/aim-cli/src/lib.rs`
- Test: `crates/aim-cli/tests/config_loading.rs`
**Step 1: Write the failing config tests**
Add tests covering:
- default config has `allow_http == false`
- config file with `allow_http = true` parses and loads correctly
**Step 2: Run the focused tests to verify failure**
Run: `cargo test --package aim-cli --test config_loading`
Expected: FAIL because `allow_http` does not exist yet
**Step 3: Add the config field**
Update `CliConfig` with:
- `allow_http: bool`
- `#[serde(default)]`
- default value `false`
**Step 4: Thread config into dispatch**
Refactor the dispatch entrypoints so the already-loaded runtime config is available during query resolution and install planning.
Preferred shape:
- add `dispatch_with_reporter_and_config(...)`
- keep existing `dispatch_with_reporter(...)` delegating to default config if needed for compatibility
- update `main.rs` to call the config-aware path
**Step 5: Run the focused tests to verify pass**
Run: `cargo test --package aim-cli --test config_loading`
Expected: PASS
**Step 6: Commit**
```bash
git add crates/aim-cli/src/config.rs crates/aim-cli/src/main.rs crates/aim-cli/src/lib.rs crates/aim-cli/tests/config_loading.rs
git commit -m "feat: add allow_http runtime config"
```
### Task 3: Enforce HTTP policy for user-supplied sources only
**Files:**
- Modify: `crates/aim-core/src/source/input.rs`
- Modify: `crates/aim-core/src/app/add.rs`
- Modify: `crates/aim-cli/src/lib.rs`
- Test: `crates/aim-core/tests/query_resolution.rs`
- Test: `crates/aim-cli/tests/end_to_end_cli.rs`
**Step 1: Write the failing behavior tests**
Add tests covering:
- direct `http://example.com/app.AppImage` fails by default
- the same input succeeds when `allow_http = true`
- explicit SourceForge `http://...` inputs follow the same rule
**Step 2: Run the focused tests to verify failure**
Run: `cargo test --package aim-cli --test end_to_end_cli`
Expected: FAIL because HTTP is currently accepted unconditionally
**Step 3: Add an explicit HTTP policy check**
Implement a narrow policy helper that is evaluated only for user-supplied source inputs before add/install proceeds.
Requirements:
- reject insecure HTTP when config disallows it
- preserve HTTPS behavior unchanged
- do not let this config affect provider-returned URLs
**Step 4: Surface a clear security error**
Ensure the user sees a message equivalent to:
- `insecure HTTP sources are disabled; set allow_http = true to permit them`
**Step 5: Run the focused tests to verify pass**
Run: `cargo test --package aim-cli --test end_to_end_cli`
Expected: PASS with both rejection and opt-in cases covered
**Step 6: Commit**
```bash
git add crates/aim-core/src/source/input.rs crates/aim-core/src/app/add.rs crates/aim-cli/src/lib.rs crates/aim-core/tests/query_resolution.rs crates/aim-cli/tests/end_to_end_cli.rs
git commit -m "feat: enforce user http policy"
```
### Task 4: Enforce HTTPS for AppImageHub provider-returned downloads
**Files:**
- Modify: `crates/aim-core/src/source/appimagehub.rs`
- Modify: `crates/aim-core/src/adapters/appimagehub.rs`
- Modify: `crates/aim-core/src/app/add.rs`
- Test: `crates/aim-core/tests/adapter_contract.rs`
- Test: `crates/aim-cli/tests/end_to_end_cli.rs`
**Step 1: Write the failing AppImageHub tests**
Add a fixture-backed case where AppImageHub returns an `http://` download URL.
Expected result:
- install planning or resolution fails with a provider-specific security error
- this remains true even when `allow_http = true`
**Step 2: Run the focused tests to verify failure**
Run: `cargo test --package aim-core --test adapter_contract`
Expected: FAIL because AppImageHub URLs are currently accepted verbatim
**Step 3: Add AppImageHub URL validation**
Validate provider-returned AppImageHub download URLs for:
- HTTPS scheme required
- clear provider-specific error path
Do not add the broader host allowlist in this task.
**Step 4: Run the focused tests to verify pass**
Run: `cargo test --package aim-core --test adapter_contract && cargo test --package aim-cli --test end_to_end_cli`
Expected: PASS
**Step 5: Commit**
```bash
git add crates/aim-core/src/source/appimagehub.rs crates/aim-core/src/adapters/appimagehub.rs crates/aim-core/src/app/add.rs crates/aim-core/tests/adapter_contract.rs crates/aim-cli/tests/end_to_end_cli.rs
git commit -m "fix: require https for appimagehub downloads"
```
### Task 5: Sanitize desktop entry display names
**Files:**
- Modify: `crates/aim-core/src/app/add.rs`
- Test: `crates/aim-core/tests/install_integration.rs`
- Test: `crates/aim-cli/tests/end_to_end_cli.rs`
**Step 1: Write the failing desktop-entry tests**
Add tests covering:
- display name containing `\nExec=evil` does not inject a second field
- display name containing control characters renders safely
- normal display names still render as expected
**Step 2: Run the focused tests to verify failure**
Run: `cargo test --package aim-core --test install_integration`
Expected: FAIL because desktop entry output currently interpolates raw display names
**Step 3: Implement minimal sanitation**
Add a helper near desktop entry rendering that:
- strips `\r` and `\n`
- replaces other control characters with spaces or removes them
- preserves ordinary printable text
Use the sanitized value only for desktop-entry rendering, not for mutating the stored app record.
**Step 4: Run the focused tests to verify pass**
Run: `cargo test --package aim-core --test install_integration`
Expected: PASS
**Step 5: Commit**
```bash
git add crates/aim-core/src/app/add.rs crates/aim-core/tests/install_integration.rs crates/aim-cli/tests/end_to_end_cli.rs
git commit -m "fix: sanitize desktop entry names"
```
### Task 6: Enforce AppImageHub MD5 integrity checks
**Files:**
- Modify: `Cargo.toml`
- Modify: `crates/aim-core/Cargo.toml`
- Modify: `crates/aim-core/src/domain/artifact.rs` or the existing artifact type definition file
- Modify: `crates/aim-core/src/app/add.rs`
- Modify: `crates/aim-core/src/integration/install.rs`
- Test: `crates/aim-core/tests/checksum_verification.rs`
- Test: `crates/aim-cli/tests/end_to_end_cli.rs`
**Step 1: Identify the artifact checksum type location**
Before editing, confirm where `ArtifactCandidate` is defined and where a provider-specific MD5 field should live.
**Step 2: Write the failing integrity tests**
Add tests covering:
- AppImageHub install succeeds with matching MD5 fixture data
- AppImageHub install fails before commit on MD5 mismatch
- AppImageHub install still succeeds when no MD5 exists
**Step 3: Run the focused tests to verify failure**
Run: `cargo test --package aim-core --test checksum_verification`
Expected: FAIL because AppImageHub MD5 is currently ignored
**Step 4: Add a separate weak-integrity field/path**
Implement a provider-specific integrity path distinct from `trusted_checksum`.
Requirements:
- store the provider MD5 on the artifact candidate or equivalent install request
- verify it after staging and before commit
- do not overload the existing trusted SHA-512 semantics
**Step 5: Add any needed dependency explicitly**
If an MD5 crate is required, add it at the workspace and crate level.
**Step 6: Run the focused tests to verify pass**
Run: `cargo test --package aim-core --test checksum_verification && cargo test --package aim-cli --test end_to_end_cli`
Expected: PASS
**Step 7: Commit**
```bash
git add Cargo.toml crates/aim-core/Cargo.toml crates/aim-core/src/app/add.rs crates/aim-core/src/integration/install.rs crates/aim-core/tests/checksum_verification.rs crates/aim-cli/tests/end_to_end_cli.rs
git commit -m "feat: verify appimagehub md5 integrity"
```
### Task 7: Harden stable IDs and managed path containment
**Files:**
- Modify: `crates/aim-core/src/app/identity.rs`
- Modify: `crates/aim-core/src/app/add.rs`
- Test: `crates/aim-core/tests/identity_resolution.rs`
- Test: `crates/aim-core/tests/install_paths.rs`
**Step 1: Write the failing hardening tests**
Add tests covering:
- identifiers normalizing to `..` are rejected
- managed install paths do not escape managed roots
**Step 2: Run the focused tests to verify failure**
Run: `cargo test --package aim-core --test identity_resolution --test install_paths`
Expected: FAIL because `..` currently survives normalization and there is no explicit containment check
**Step 3: Implement identity and path validation**
Add:
- explicit normalized-ID rejection for `..`
- path containment validation before install proceeds
Keep the implementation minimal and deterministic.
**Step 4: Run the focused tests to verify pass**
Run: `cargo test --package aim-core --test identity_resolution --test install_paths`
Expected: PASS
**Step 5: Commit**
```bash
git add crates/aim-core/src/app/identity.rs crates/aim-core/src/app/add.rs crates/aim-core/tests/identity_resolution.rs crates/aim-core/tests/install_paths.rs
git commit -m "fix: harden stable id paths"
```
### Task 8: Add external helper audit logging and adversarial regression coverage
**Files:**
- Modify: `crates/aim-core/src/integration/refresh.rs`
- Modify: `crates/aim-core/src/source/appimagehub.rs`
- Test: `crates/aim-core/tests/adapter_contract.rs`
- Test: `crates/aim-core/tests/install_integration.rs`
- Test: `crates/aim-cli/tests/end_to_end_cli.rs`
**Step 1: Write the failing or missing regression tests**
Add adversarial cases for:
- malformed AppImageHub XML or missing fields handled cleanly
- malicious display names in fixture-backed install flows
- helper execution paths producing expected warnings/loggable branches
**Step 2: Implement minimal logging**
Add debug-level logging around helper execution in `refresh.rs`.
**Step 3: Run focused tests**
Run: `cargo test --package aim-core --test adapter_contract --test install_integration && cargo test --package aim-cli --test end_to_end_cli`
Expected: PASS
**Step 4: Commit**
```bash
git add crates/aim-core/src/integration/refresh.rs crates/aim-core/src/source/appimagehub.rs crates/aim-core/tests/adapter_contract.rs crates/aim-core/tests/install_integration.rs crates/aim-cli/tests/end_to_end_cli.rs
git commit -m "test: cover security edge cases"
```
### Task 9: Full verification and final docs pass
**Files:**
- Modify: `.plans/012-security-hardening-config-and-integrity/2026-03-21-security-hardening-config-and-integrity-design.md` if implementation drifted
- Modify: `.plans/012-security-hardening-config-and-integrity/2026-03-21-security-hardening-config-and-integrity-implementation-plan.md` if task wording drifted
- Modify: `.architecture/security-issues.md` if final wording needs adjustment
**Step 1: Run formatting and full verification**
Run:
```bash
cargo fmt --all
cargo test --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
```
Expected: all commands succeed.
**Step 2: Re-read the security docs**
Confirm the final README and `.architecture/security-issues.md` text still matches the implementation.
**Step 3: Commit**
```bash
git add .plans/012-security-hardening-config-and-integrity .architecture/security-issues.md README.md
git commit -m "docs: record security hardening plan"
```