You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# Security (mirrors .github/workflows/security.yml where tools are installed)
39
+
./dev/scripts/security-check.sh
40
+
# Individual checks if needed:
41
+
# cargo audit
42
+
# cargo deny check
43
+
# gitleaks detect --source . --no-banner
37
44
```
38
45
39
46
## Screenshots / recordings (if UI changes)
@@ -69,6 +76,12 @@ Include before/after images or a short GIF. Update files in `Images/` if relevan
69
76
-[ ] Code degrades gracefully if `pacman`/`paru`/`yay` are unavailable
70
77
-[ ] No breaking changes (or clearly documented if intentional)
71
78
79
+
**Security (CI):**
80
+
-[ ] Ran `./dev/scripts/security-check.sh` before opening the PR (local mirror of the Security workflow: rustfmt, clippy, `cargo audit`, `cargo deny check`, gitleaks — skipped steps print install hints)
81
+
-[ ] After adding or updating dependencies: `cargo audit` and `cargo deny check` pass (`deny.toml`); no new high-severity or license issues that would fail GitHub **dependency review** on this PR
82
+
-[ ] No secrets or credential-like placeholders that would trip **gitleaks** (see `.gitleaks.toml` for allowlisted paths if you must add test fixtures)
83
+
-[ ] Follows secure coding rules in `AGENTS.md` / `CLAUDE.md` (shell quoting, credentials, HTTP, paths) — see `dev/SECURITY_REMEDIATION_GUIDE.md` for remediation patterns
84
+
72
85
**Other:**
73
86
-[ ] Not a packaging change for AUR (otherwise propose in `pacsea-bin` or `pacsea-git` repos)
| Data flow / coupling | Manual design review; no lint — match existing module patterns | N/A |
161
161
162
+
## Security rules
163
+
164
+
These rules exist to prevent specific vulnerability classes identified in `dev/SECURITY_AUDIT_REPORT.md`. They are **mandatory** — not suggestions.
165
+
166
+
### Shell command construction
167
+
168
+
-**Never interpolate package names, file paths, or user input directly into shell command strings.** Always pass them through `shell_single_quote()` from `src/install/utils.rs` first.
169
+
- When building shell commands with multiple package names, quote **each name individually** before joining:
- When adding a new function in `src/install/` that constructs shell commands, verify that **every** variable fragment interpolated into `format!()` is either:
175
+
1. A constant/static string, **or**
176
+
2. Passed through `shell_single_quote()`, **or**
177
+
3. Validated against `^[a-z\d@._+-]+$` before use.
178
+
-**Never use `format!()` with `sh -c` and unsanitized user data.** Prefer `Command::new().arg()` argument passing over string interpolation when possible — `Command` arguments are not interpreted by a shell.
179
+
- On Windows, never pass unescaped strings into `cmd /C` or `cmd /K`. Use PowerShell with proper quoting or escape `&`, `|`, `>`, `<`, `^` for cmd.exe.
180
+
181
+
### Password and credential handling
182
+
183
+
-**Never log passwords.** Any function that writes command strings to disk (log files, temp scripts) must redact password pipe patterns (`printf '%s\n' '...' | sudo -S`) before writing. Replace the password with `[REDACTED]`.
184
+
-**Never store passwords in plain `String`.** Use `SecureString` (zeroize-backed) from `src/state/types.rs` for all password fields. If `SecureString` does not exist yet, use `String` but add a `// TODO: migrate to SecureString` comment and a `zeroize` call on the containing struct's `Drop`.
185
+
- When creating files that might contain sensitive data (log files, temp scripts), use `OpenOptions::mode(0o600)` on Unix to prevent world-readable permissions.
186
+
- Never include passwords or credentials in `tracing::info!`, `tracing::debug!`, or `tracing::warn!` output. If you need to log that a password was provided, log `password_provided = true` — never the value.
187
+
188
+
### Network and HTTP
189
+
190
+
- All curl invocations must go through `curl_args()` in `src/util/mod.rs`. Do not construct raw curl commands.
191
+
-`curl_args()` must include `--max-filesize 10485760` (10 MB) to prevent memory exhaustion from oversized responses. If this is not yet present, add it.
192
+
- Never disable TLS certificate verification (`-k` / `--insecure`) on Linux builds. The Windows `-k` flag is a known issue tracked for removal.
193
+
- URLs constructed from user input or API data must be validated to start with `http://` or `https://` before passing to curl. See `looks_like_http_url()` in `src/logic/repos/apply_plan.rs` for the pattern.
194
+
195
+
### File system safety
196
+
197
+
-**Validate all paths before writing.** Use or extend `is_safe_abs_path()` from `src/logic/repos/apply_plan.rs` for any privileged file write. Reject paths containing `..`.
198
+
-**Create temp files atomically.** Use `OpenOptions::create_new(true).mode(0o700)` instead of `fs::write()` followed by `set_permissions()`. The `create_new` flag prevents symlink-following TOCTOU races.
199
+
- When writing files under `~/.config/pacsea/`, create parent directories with `create_dir_all` but do not set overly permissive modes. Default umask-derived permissions are acceptable for non-sensitive files; use `0o600` for anything that could contain credentials.
200
+
201
+
### Test environment overrides
202
+
203
+
- Functions that check `PACSEA_INTEGRATION_TEST` or `PACSEA_TEST_*` environment variables must **not** bypass security checks in release builds. Gate them with `#[cfg(debug_assertions)]` or `#[cfg(test)]` so they compile to no-ops in release mode.
204
+
- Never add new environment-variable-based test overrides that skip authentication, privilege checks, or input validation without a `#[cfg(debug_assertions)]` guard.
205
+
206
+
### Dependency management
207
+
208
+
- Run `cargo audit` after adding or updating dependencies. Resolve all **critical** and **high** advisories before merging.
209
+
- Prefer direct dependencies over transitive ones for security-sensitive functionality. If a transitive dependency has an advisory, check if the parent crate can be updated to pull a fixed version.
210
+
- Do not add dependencies that require `unsafe` for their core functionality unless there is no safe alternative and the crate is well-maintained.
211
+
212
+
### Audit reference
213
+
214
+
Full findings and remediation steps: `dev/SECURITY_AUDIT_REPORT.md` and `dev/SECURITY_REMEDIATION_GUIDE.md`.
215
+
162
216
## General rules
163
217
- No unsolicited `*.md` / wiki / README edits.
164
218
- Preserve dry-run semantics and graceful handling of missing external tools.
| Data flow / coupling | Manual design review; no lint — match existing module patterns | N/A |
161
161
162
+
## Security rules
163
+
164
+
These rules exist to prevent specific vulnerability classes identified in `dev/SECURITY_AUDIT_REPORT.md`. They are **mandatory** — not suggestions.
165
+
166
+
### Shell command construction
167
+
168
+
-**Never interpolate package names, file paths, or user input directly into shell command strings.** Always pass them through `shell_single_quote()` from `src/install/utils.rs` first.
169
+
- When building shell commands with multiple package names, quote **each name individually** before joining:
- When adding a new function in `src/install/` that constructs shell commands, verify that **every** variable fragment interpolated into `format!()` is either:
175
+
1. A constant/static string, **or**
176
+
2. Passed through `shell_single_quote()`, **or**
177
+
3. Validated against `^[a-z\d@._+-]+$` before use.
178
+
-**Never use `format!()` with `sh -c` and unsanitized user data.** Prefer `Command::new().arg()` argument passing over string interpolation when possible — `Command` arguments are not interpreted by a shell.
179
+
- On Windows, never pass unescaped strings into `cmd /C` or `cmd /K`. Use PowerShell with proper quoting or escape `&`, `|`, `>`, `<`, `^` for cmd.exe.
180
+
181
+
### Password and credential handling
182
+
183
+
-**Never log passwords.** Any function that writes command strings to disk (log files, temp scripts) must redact password pipe patterns (`printf '%s\n' '...' | sudo -S`) before writing. Replace the password with `[REDACTED]`.
184
+
-**Never store passwords in plain `String`.** Use `SecureString` (zeroize-backed) from `src/state/types.rs` for all password fields. If `SecureString` does not exist yet, use `String` but add a `// TODO: migrate to SecureString` comment and a `zeroize` call on the containing struct's `Drop`.
185
+
- When creating files that might contain sensitive data (log files, temp scripts), use `OpenOptions::mode(0o600)` on Unix to prevent world-readable permissions.
186
+
- Never include passwords or credentials in `tracing::info!`, `tracing::debug!`, or `tracing::warn!` output. If you need to log that a password was provided, log `password_provided = true` — never the value.
187
+
188
+
### Network and HTTP
189
+
190
+
- All curl invocations must go through `curl_args()` in `src/util/mod.rs`. Do not construct raw curl commands.
191
+
-`curl_args()` must include `--max-filesize 10485760` (10 MB) to prevent memory exhaustion from oversized responses. If this is not yet present, add it.
192
+
- Never disable TLS certificate verification (`-k` / `--insecure`) on Linux builds. The Windows `-k` flag is a known issue tracked for removal.
193
+
- URLs constructed from user input or API data must be validated to start with `http://` or `https://` before passing to curl. See `looks_like_http_url()` in `src/logic/repos/apply_plan.rs` for the pattern.
194
+
195
+
### File system safety
196
+
197
+
-**Validate all paths before writing.** Use or extend `is_safe_abs_path()` from `src/logic/repos/apply_plan.rs` for any privileged file write. Reject paths containing `..`.
198
+
-**Create temp files atomically.** Use `OpenOptions::create_new(true).mode(0o700)` instead of `fs::write()` followed by `set_permissions()`. The `create_new` flag prevents symlink-following TOCTOU races.
199
+
- When writing files under `~/.config/pacsea/`, create parent directories with `create_dir_all` but do not set overly permissive modes. Default umask-derived permissions are acceptable for non-sensitive files; use `0o600` for anything that could contain credentials.
200
+
201
+
### Test environment overrides
202
+
203
+
- Functions that check `PACSEA_INTEGRATION_TEST` or `PACSEA_TEST_*` environment variables must **not** bypass security checks in release builds. Gate them with `#[cfg(debug_assertions)]` or `#[cfg(test)]` so they compile to no-ops in release mode.
204
+
- Never add new environment-variable-based test overrides that skip authentication, privilege checks, or input validation without a `#[cfg(debug_assertions)]` guard.
205
+
206
+
### Dependency management
207
+
208
+
- Run `cargo audit` after adding or updating dependencies. Resolve all **critical** and **high** advisories before merging.
209
+
- Prefer direct dependencies over transitive ones for security-sensitive functionality. If a transitive dependency has an advisory, check if the parent crate can be updated to pull a fixed version.
210
+
- Do not add dependencies that require `unsafe` for their core functionality unless there is no safe alternative and the crate is well-maintained.
211
+
212
+
### Audit reference
213
+
214
+
Full findings and remediation steps: `dev/SECURITY_AUDIT_REPORT.md` and `dev/SECURITY_REMEDIATION_GUIDE.md`.
215
+
162
216
## General rules
163
217
- No unsolicited `*.md` / wiki / README edits.
164
218
- Preserve dry-run semantics and graceful handling of missing external tools.
-[ ] Updated docs if behavior, options, or keybinds changed
275
281
-[ ] For UI changes: included screenshots and updated `Images/` if applicable
276
282
-[ ] Changes respect `--dry-run` and degrade gracefully if `pacman`/`paru`/`yay` are unavailable
283
+
-[ ]`cargo audit` clean (no new high/critical advisories introduced)
284
+
-[ ] Shell commands use `shell_single_quote()` for external data (package names, paths)
277
285
-[ ] If config keys changed: updated README/wiki sections for `settings.conf`, `theme.conf`, and `keybinds.conf`
278
286
-[ ] Not a packaging change for AUR (otherwise propose in `pacsea-bin` or `pacsea-git` repos)
279
287
@@ -308,6 +316,13 @@ If new config keys were added, document them here.
308
316
- Update README if it's a major feature
309
317
- Ensure backward compatibility when possible
310
318
319
+
### Security
320
+
-**Shell commands**: Never interpolate external data (package names, paths, user input) directly into shell strings. Use `shell_single_quote()` from `src/install/utils.rs` or pass arguments via `Command::new().arg()`.
321
+
-**Credentials**: Never log passwords or tokens. Redact sensitive values before writing to disk. Use `0o600` permissions for files that could contain credential traces.
322
+
-**Network**: All HTTP requests go through `curl_args()`. Never disable TLS verification on Linux. Validate URLs start with `http://` or `https://` before fetching.
323
+
-**Dependencies**: Run `cargo audit` after adding or updating crates. High/critical advisories block merges.
324
+
- Full rules and rationale: [`CLAUDE.md` → Security rules](CLAUDE.md) and [`dev/SECURITY_REMEDIATION_GUIDE.md`](dev/SECURITY_REMEDIATION_GUIDE.md).
325
+
311
326
### Platform behavior
312
327
-**Dry-run**: All commands must respect `--dry-run` flag
313
328
-**Graceful degradation**: Commands must degrade gracefully if `pacman`/`paru`/`yay` are unavailable
0 commit comments