Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9107e261f4 | ||
|
|
d699cdcff4 | ||
|
|
a3cee2756c | ||
|
|
5b0c623a8d |
No files matched your search
@@ -4,14 +4,20 @@ on:
|
|||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
schedule:
|
||||||
|
- cron: '23 4 * * 1'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
linux:
|
linux:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||||
|
- name: Install current Codex CLI for schema validation
|
||||||
|
run: npm install --global @openai/codex@latest
|
||||||
|
- name: Bash syntax
|
||||||
|
run: find scripts shared/hooks -name '*.sh' -print0 | xargs -0 -n1 bash -n
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./scripts/build.sh
|
run: REQUIRE_CODEX_SCHEMA=true ./scripts/build.sh
|
||||||
- name: Doctor
|
- name: Doctor
|
||||||
run: ./scripts/doctor.sh
|
run: ./scripts/doctor.sh
|
||||||
- name: Platform package tests
|
- name: Platform package tests
|
||||||
@@ -20,7 +26,7 @@ jobs:
|
|||||||
run: ./scripts/test-managed-install.sh
|
run: ./scripts/test-managed-install.sh
|
||||||
- name: Build validation tests
|
- name: Build validation tests
|
||||||
run: ./scripts/test-build-validation.sh
|
run: ./scripts/test-build-validation.sh
|
||||||
- name: Install dry run (isolated HOME)
|
- name: Install dry run
|
||||||
run: |
|
run: |
|
||||||
export HOME="$RUNNER_TEMP/isolated-home"
|
export HOME="$RUNNER_TEMP/isolated-home"
|
||||||
mkdir -p "$HOME"
|
mkdir -p "$HOME"
|
||||||
@@ -29,10 +35,24 @@ jobs:
|
|||||||
windows:
|
windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
|
||||||
|
- name: Install current Codex CLI for schema validation
|
||||||
|
shell: powershell
|
||||||
|
run: npm install --global @openai/codex@latest
|
||||||
|
- name: PowerShell syntax
|
||||||
|
shell: powershell
|
||||||
|
run: |
|
||||||
|
$errors = @()
|
||||||
|
Get-ChildItem scripts,shared/hooks -Recurse -Filter *.ps1 | ForEach-Object {
|
||||||
|
$tokens = $null
|
||||||
|
$parseErrors = $null
|
||||||
|
[void][System.Management.Automation.Language.Parser]::ParseFile($_.FullName, [ref]$tokens, [ref]$parseErrors)
|
||||||
|
$errors += $parseErrors
|
||||||
|
}
|
||||||
|
if ($errors.Count) { $errors | ForEach-Object { Write-Error $_ }; exit 1 }
|
||||||
- name: Build
|
- name: Build
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: .\scripts\build.ps1
|
run: $env:REQUIRE_CODEX_SCHEMA = 'true'; .\scripts\build.ps1
|
||||||
- name: Doctor
|
- name: Doctor
|
||||||
shell: powershell
|
shell: powershell
|
||||||
run: .\scripts\doctor.ps1
|
run: .\scripts\doctor.ps1
|
||||||
@@ -47,8 +67,4 @@ jobs:
|
|||||||
run: .\scripts\test-build-validation.ps1
|
run: .\scripts\test-build-validation.ps1
|
||||||
- name: Install dry run
|
- name: Install dry run
|
||||||
shell: powershell
|
shell: powershell
|
||||||
# -DryRun performs no writes, so it is safe to run against the runner's
|
|
||||||
# real profile path. [Environment]::GetFolderPath('UserProfile') reads
|
|
||||||
# from the Windows profile API on PowerShell 5.1, not $env:USERPROFILE,
|
|
||||||
# so overriding that variable would not relocate it anyway.
|
|
||||||
run: .\scripts\install.ps1 -DryRun -Client Both -Platform Windows
|
run: .\scripts\install.ps1 -DryRun -Client Both -Platform Windows
|
||||||
@@ -25,7 +25,8 @@ into platform-specific packages that can be inspected before they are installed.
|
|||||||
or deleting them.
|
or deleting them.
|
||||||
- Dry-run support (no writes, no backups, no plugin changes) and timestamped, per-run backup directories.
|
- Dry-run support (no writes, no backups, no plugin changes) and timestamped, per-run backup directories.
|
||||||
- Shared safety, notification, validation, and status-line hooks.
|
- Shared safety, notification, validation, and status-line hooks.
|
||||||
- User-level plugin installation for Ponytail, i-have-adhd, Superpowers, and Context7; updates only with
|
- User-level plugin installation for Ponytail, i-have-adhd, Superpowers, Context7, Caveman, Humanizer, Impeccable,
|
||||||
|
and Anthropic Frontend Design; updates only with
|
||||||
`-UpdatePlugins`/`--update-plugins`.
|
`-UpdatePlugins`/`--update-plugins`.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|||||||
@@ -7,6 +7,14 @@ git.md rules-git Git operations such as commits, branches, or merges
|
|||||||
microsoft.md rules-microsoft Microsoft 365, Azure DevOps, or Teams operations
|
microsoft.md rules-microsoft Microsoft 365, Azure DevOps, or Teams operations
|
||||||
refactoring.md rules-refactoring refactoring existing code without changing behavior
|
refactoring.md rules-refactoring refactoring existing code without changing behavior
|
||||||
security.md rules-security any software development task: implementing, modifying, debugging, reviewing, testing, or configuring code, scripts, hooks, or infrastructure
|
security.md rules-security any software development task: implementing, modifying, debugging, reviewing, testing, or configuring code, scripts, hooks, or infrastructure
|
||||||
|
security-auth.md rules-security-auth authentication, authorization, sessions, tokens, permissions, or tenant-boundary work
|
||||||
|
security-web.md rules-security-web web, browser, frontend, cookie, redirect, or XSS/CSRF work
|
||||||
|
security-api.md rules-security-api HTTP API, request handling, serialization, or endpoint work
|
||||||
|
security-data.md rules-security-data database, query, persistence, sensitive-data, or multi-tenant work
|
||||||
|
security-files.md rules-security-files file, upload, archive, path, process, IPC, or deserialization work
|
||||||
|
security-network.md rules-security-network network, URL fetch, proxy, outbound request, TLS, or SSRF work
|
||||||
|
security-crypto.md rules-security-crypto cryptography, secrets, credentials, key, or token work
|
||||||
|
security-supply-chain.md rules-security-supply-chain dependency, package, plugin, build, deployment, or CI supply-chain work
|
||||||
typescript.md rules-typescript TypeScript or modern ECMAScript implementation work
|
typescript.md rules-typescript TypeScript or modern ECMAScript implementation work
|
||||||
ui-ux.md rules-ui-ux UI or UX design and interaction decisions
|
ui-ux.md rules-ui-ux UI or UX design and interaction decisions
|
||||||
wpf.md rules-wpf WPF, XAML, or MVVM desktop UI work
|
wpf.md rules-wpf WPF, XAML, or MVVM desktop UI work
|
||||||
|
@@ -8,6 +8,7 @@ status_line = ["model", "reasoning", "project-name", "git-branch", "context-wind
|
|||||||
[agents]
|
[agents]
|
||||||
enabled = true
|
enabled = true
|
||||||
max_concurrent_threads_per_session = 5
|
max_concurrent_threads_per_session = 5
|
||||||
|
max_depth = 1
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
hooks = true
|
hooks = true
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
name claude_marketplace claude_plugin codex_marketplace codex_plugin
|
name claude_marketplace claude_plugin codex_marketplace codex_plugin codex_method codex_source codex_skill
|
||||||
Ponytail DietrichGebert/ponytail ponytail@ponytail DietrichGebert/ponytail ponytail@ponytail
|
Ponytail DietrichGebert/ponytail ponytail@ponytail DietrichGebert/ponytail ponytail@ponytail plugin - -
|
||||||
i-have-adhd ayghri/i-have-adhd i-have-adhd@i-have-adhd ayghri/i-have-adhd i-have-adhd@i-have-adhd
|
i-have-adhd ayghri/i-have-adhd i-have-adhd@i-have-adhd ayghri/i-have-adhd i-have-adhd@i-have-adhd plugin - -
|
||||||
Superpowers - superpowers@claude-plugins-official openai-curated-remote superpowers@openai-curated-remote
|
Superpowers - superpowers@claude-plugins-official openai-curated-remote superpowers@openai-curated-remote plugin - -
|
||||||
Context7 upstash/context7 context7@context7-marketplace upstash/context7 context7@context7-marketplace
|
Context7 upstash/context7 context7@context7-marketplace upstash/context7 context7@context7-marketplace plugin - -
|
||||||
|
Caveman JuliusBrussee/caveman caveman@caveman thinkhome-org/caveman-codex caveman@thinkhome-caveman plugin - -
|
||||||
|
Humanizer blader/humanizer humanizer@humanizer - - skill blader/humanizer -
|
||||||
|
Impeccable pbakaus/impeccable impeccable@impeccable - - impeccable - -
|
||||||
|
Anthropic Frontend Design anthropics/claude-plugins-official frontend-design@claude-plugins-official - - skill anthropics/skills frontend-design
|
||||||
|
@@ -1,13 +1,11 @@
|
|||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
Codex receives a generated global `AGENTS.md`, agent TOML files, skills, rule files, and a `config.toml` adapter with workspace sandboxing, interactive approval boundaries, automatic approval review, enabled sub-agents, and a five-thread concurrency limit (`max_concurrent_threads_per_session`, the current canonical key; the legacy `max_threads` alias is not emitted). Claude Code receives a generated global `CLAUDE.md`, agent Markdown files, skills, and `settings.json` with the `auto` permission mode, explicit `Agent` permission, and a five-operation tool/sub-agent concurrency limit. The exact installed locations are resolved from the user profile at install time; no machine-specific absolute path is stored in the repository.
|
Codex receives a generated global `AGENTS.md`, agent TOML files, skills, rule files, and a `config.toml` adapter. It keeps workspace sandboxing, automatic approval review, `agents.enabled = true`, `agents.max_concurrent_threads_per_session = 5`, and `agents.max_depth = 1`. Claude Code receives a generated global `CLAUDE.md`, agent Markdown files, skills, and `settings.json` with `auto` permissions, explicit `Agent` permission, and five-operation concurrency. Installation resolves user paths at runtime; the repository contains no machine-specific paths.
|
||||||
|
|
||||||
Claude's rule loading differs from Codex's by design: `general.md` is the only rule shipped as a plain, always-applied file (its text is also embedded directly in `CLAUDE.md`). Every technology- or situation-specific rule in `shared/rules/` is instead generated as a skill under `skills/rules/`, driven by `adapters/claude/rule-skills.tsv` (rule file, skill name, trigger description). Only a skill's name and description are ever permanently in context; Claude loads the full rule text only when it invokes the skill. Codex is unaffected — it keeps receiving every rule as a plain file and is told to load the matching one by path, exactly as before.
|
Codex keeps rules as files and loads only applicable focused rules. Claude embeds `general.md` and generates the remaining rules as skills from `adapters/claude/rule-skills.tsv`. `security.md` is a short universal baseline; focused security rules load only for authentication, web, API, data, files, network, cryptography, and supply-chain work.
|
||||||
|
|
||||||
Codex's current configuration schema has no `agents.max_depth` or other agent-recursion-depth key. The only `max_depth`-shaped setting in the schema is `network_proxy.glob_scan_max_depth`, which bounds glob-pattern expansion for the network proxy feature and is unrelated to agents; Claude Code's settings likewise expose no comparable key. The repository does not emit either as an invented key.
|
`agents.max_depth = 1` limits V1 Codex subagent recursion. `features.multi_agent_v2` is not enabled. If enabled later, V2 takes precedence over `agents.enabled` and ignores `agents.max_depth`.
|
||||||
|
|
||||||
`[agents].enabled = true` (set explicitly, matching its own documented default) is the current, documented way to enable Codex's multi-agent tools. A separate `[features].multi_agent` toggle exists in the schema but is not set here, since `[agents].enabled` already covers it and setting both would be redundant. `multi_agent_v2` does not appear in the current documented schema at all — it surfaced only in upstream issue titles describing an internal/experimental flag — so it is deliberately not configured.
|
The build parses TOML with Python's standard-library `tomllib`, validates the emitted Claude settings shape, and uses `codex --strict-config` against an isolated generated configuration when Codex is available. This rejects malformed and unknown Codex configuration keys for the installed CLI version.
|
||||||
|
|
||||||
Client settings remain thin adapters. Shared semantics remain in `shared/`.
|
Client settings remain thin adapters. Shared semantics remain in `shared/`. User plugins are managed separately through `adapters/plugins.tsv` and client-native installation commands.
|
||||||
|
|
||||||
User plugins are managed separately through `adapters/plugins.tsv` and the client-native plugin commands. They are not copied into `generated/` because each client owns its plugin cache and authentication state.
|
|
||||||
+3
-1
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
The user-level plugin manifest is `adapters/plugins.tsv`. It maps each logical plugin to the marketplace selector understood by Claude Code and Codex.
|
The user-level plugin manifest is `adapters/plugins.tsv`. It maps each logical plugin to the marketplace selector understood by Claude Code and Codex.
|
||||||
|
|
||||||
The current baseline includes Ponytail, i-have-adhd, Superpowers, and Context7. The install script operates at user scope and is idempotent: a normal run only installs missing plugins (a disabled but already-installed Claude plugin is re-enabled). Pass `-UpdatePlugins`/`--update-plugins` to also update plugins that are already installed, so a configuration update never silently updates third-party plugin code.
|
The current baseline includes Ponytail, i-have-adhd, Superpowers, Context7, Caveman, Humanizer, Impeccable, and Anthropic Frontend Design. The install script operates at user scope and is idempotent: a normal run only installs missing plugins (a disabled but already-installed Claude plugin is re-enabled). Pass `-UpdatePlugins`/`--update-plugins` to also update plugins that are already installed, so a configuration update never silently updates third-party plugin code.
|
||||||
|
|
||||||
|
Codex receives Caveman through its native plugin adapter. Humanizer and Anthropic Frontend Design are installed through the cross-agent Skills CLI; Impeccable uses its provider-aware Codex installer. All four are therefore available to both clients, although Codex does not expose all four as marketplace plugins.
|
||||||
|
|
||||||
Plugin installation requires the corresponding client CLI, network access, and any authentication required by the plugin. Context7 may open an OAuth flow. Codex or plugin hooks may require a trust review in `/hooks`. The scripts never install plugins during a build or doctor run and never install them when `--dry-run` or `-DryRun` is used.
|
Plugin installation requires the corresponding client CLI, network access, and any authentication required by the plugin. Context7 may open an OAuth flow. Codex or plugin hooks may require a trust review in `/hooks`. The scripts never install plugins during a build or doctor run and never install them when `--dry-run` or `-DryRun` is used.
|
||||||
|
|
||||||
|
|||||||
+38
-7
@@ -12,7 +12,7 @@ $pluginEntries = @(Import-Csv -LiteralPath $pluginManifest -Delimiter ([char]9))
|
|||||||
if ($pluginEntries.Count -eq 0) { throw 'Plugin manifest must define at least one plugin.' }
|
if ($pluginEntries.Count -eq 0) { throw 'Plugin manifest must define at least one plugin.' }
|
||||||
$pluginNames = @()
|
$pluginNames = @()
|
||||||
foreach ($pluginEntry in $pluginEntries) {
|
foreach ($pluginEntry in $pluginEntries) {
|
||||||
foreach ($field in @('name','claude_plugin','codex_plugin')) {
|
foreach ($field in @('name','claude_plugin','codex_method')) {
|
||||||
if ([string]::IsNullOrWhiteSpace($pluginEntry.$field)) { throw "Missing $field for plugin $($pluginEntry.name)." }
|
if ([string]::IsNullOrWhiteSpace($pluginEntry.$field)) { throw "Missing $field for plugin $($pluginEntry.name)." }
|
||||||
}
|
}
|
||||||
if ($pluginNames -contains $pluginEntry.name) { throw "Duplicate plugin name in manifest: $($pluginEntry.name)" }
|
if ($pluginNames -contains $pluginEntry.name) { throw "Duplicate plugin name in manifest: $($pluginEntry.name)" }
|
||||||
@@ -52,6 +52,32 @@ function Read-Field($path, $name) {
|
|||||||
function Quote-Toml($value) {
|
function Quote-Toml($value) {
|
||||||
return ('"' + $value.Replace('\','\\').Replace('"','\"').Replace("`r",'').Replace("`n",'\n') + '"')
|
return ('"' + $value.Replace('\','\\').Replace('"','\"').Replace("`r",'').Replace("`n",'\n') + '"')
|
||||||
}
|
}
|
||||||
|
function Test-CodexSchema($configPath) {
|
||||||
|
if (-not (Get-Command codex -ErrorAction SilentlyContinue)) {
|
||||||
|
if ($env:REQUIRE_CODEX_SCHEMA -eq 'true') { throw 'Codex CLI is required for schema validation.' }
|
||||||
|
Write-Warning 'Codex CLI unavailable; skipped Codex schema validation.'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$tempHome = Join-Path ([System.IO.Path]::GetTempPath()) ("codex-schema-" + [Guid]::NewGuid())
|
||||||
|
$previousCodexHome = $env:CODEX_HOME
|
||||||
|
try {
|
||||||
|
New-Item $tempHome -ItemType Directory -Force | Out-Null
|
||||||
|
Copy-Item $configPath (Join-Path $tempHome 'config.toml') -Force
|
||||||
|
$env:CODEX_HOME = $tempHome
|
||||||
|
$previousErrorActionPreference = $ErrorActionPreference
|
||||||
|
try {
|
||||||
|
$ErrorActionPreference = 'Continue'
|
||||||
|
$schemaOutput = @(& codex --strict-config --help 2>&1)
|
||||||
|
$schemaExitCode = $LASTEXITCODE
|
||||||
|
} finally {
|
||||||
|
$ErrorActionPreference = $previousErrorActionPreference
|
||||||
|
}
|
||||||
|
if ($schemaExitCode -ne 0) { throw "Codex schema validation failed: $configPath`n$($schemaOutput -join [Environment]::NewLine)" }
|
||||||
|
} finally {
|
||||||
|
$env:CODEX_HOME = $previousCodexHome
|
||||||
|
Remove-Item $tempHome -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
& (Join-Path $root 'shared/hooks/scripts/Test-SessionConfig.ps1') -RepositoryRoot $root
|
& (Join-Path $root 'shared/hooks/scripts/Test-SessionConfig.ps1') -RepositoryRoot $root
|
||||||
|
|
||||||
@@ -75,6 +101,14 @@ Detect the languages, frameworks, tools, and change areas from the repository an
|
|||||||
|
|
||||||
Load rule files when their subject applies:
|
Load rule files when their subject applies:
|
||||||
|
|
||||||
|
- rules/security-auth.md for authentication, authorization, sessions, tokens, permissions, or tenant boundaries.
|
||||||
|
- rules/security-web.md for browser, frontend, cookie, redirect, XSS, or CSRF work.
|
||||||
|
- rules/security-api.md for HTTP APIs, request handling, serialization, or endpoints.
|
||||||
|
- rules/security-data.md for databases, persistence, sensitive data, or multi-tenancy.
|
||||||
|
- rules/security-files.md for files, uploads, archives, paths, processes, IPC, or deserialization.
|
||||||
|
- rules/security-network.md for network access, URLs, TLS, proxies, or SSRF.
|
||||||
|
- rules/security-crypto.md for cryptography, secrets, credentials, keys, or tokens.
|
||||||
|
- rules/security-supply-chain.md for dependencies, packages, plugins, builds, deployments, or CI.
|
||||||
- rules/angular.md for Angular work.
|
- rules/angular.md for Angular work.
|
||||||
- rules/typescript.md for TypeScript work.
|
- rules/typescript.md for TypeScript work.
|
||||||
- rules/csharp.md for C# or .NET work.
|
- rules/csharp.md for C# or .NET work.
|
||||||
@@ -154,13 +188,10 @@ foreach ($platform in @('windows','linux')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$tomlPath = Join-Path $output "codex-$platform/config.toml"
|
$tomlPath = Join-Path $output "codex-$platform/config.toml"
|
||||||
$tomlContent = Get-Content -LiteralPath $tomlPath -Raw
|
|
||||||
if (([regex]::Matches($tomlContent, '(?<!\\)"')).Count % 2 -ne 0) { throw "Generated Codex config.toml has unbalanced quotes: $tomlPath" }
|
|
||||||
if (([regex]::Matches($tomlContent, '\[')).Count -ne ([regex]::Matches($tomlContent, '\]')).Count) { throw "Generated Codex config.toml has unbalanced brackets: $tomlPath" }
|
|
||||||
|
|
||||||
$settingsPath = Join-Path $output "claude-$platform/settings.json"
|
$settingsPath = Join-Path $output "claude-$platform/settings.json"
|
||||||
try { Get-Content -LiteralPath $settingsPath -Raw | ConvertFrom-Json | Out-Null }
|
& python (Join-Path $root 'scripts/validate-config.py') $tomlPath $settingsPath
|
||||||
catch { throw "Generated Claude settings.json is not valid JSON: $settingsPath" }
|
if ($LASTEXITCODE -ne 0) { throw "Generated configuration validation failed for $platform." }
|
||||||
|
Test-CodexSchema $tomlPath
|
||||||
}
|
}
|
||||||
|
|
||||||
$leftoverPlaceholders = @(Get-ChildItem $output -File -Recurse | ForEach-Object {
|
$leftoverPlaceholders = @(Get-ChildItem $output -File -Recurse | ForEach-Object {
|
||||||
|
|||||||
+19
-12
@@ -84,6 +84,14 @@ Detect the languages, frameworks, tools, and change areas from the repository an
|
|||||||
|
|
||||||
Load rule files when their subject applies:
|
Load rule files when their subject applies:
|
||||||
|
|
||||||
|
- rules/security-auth.md for authentication, authorization, sessions, tokens, permissions, or tenant boundaries.
|
||||||
|
- rules/security-web.md for browser, frontend, cookie, redirect, XSS, or CSRF work.
|
||||||
|
- rules/security-api.md for HTTP APIs, request handling, serialization, or endpoints.
|
||||||
|
- rules/security-data.md for databases, persistence, sensitive data, or multi-tenancy.
|
||||||
|
- rules/security-files.md for files, uploads, archives, paths, processes, IPC, or deserialization.
|
||||||
|
- rules/security-network.md for network access, URLs, TLS, proxies, or SSRF.
|
||||||
|
- rules/security-crypto.md for cryptography, secrets, credentials, keys, or tokens.
|
||||||
|
- rules/security-supply-chain.md for dependencies, packages, plugins, builds, deployments, or CI.
|
||||||
- rules/angular.md for Angular work.
|
- rules/angular.md for Angular work.
|
||||||
- rules/typescript.md for TypeScript work.
|
- rules/typescript.md for TypeScript work.
|
||||||
- rules/csharp.md for C# or .NET work.
|
- rules/csharp.md for C# or .NET work.
|
||||||
@@ -180,19 +188,18 @@ for client in codex claude; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
toml_path="$output/codex-$platform/config.toml"
|
toml_path="$output/codex-$platform/config.toml"
|
||||||
quote_count=$(grep -o '"' "$toml_path" | wc -l)
|
|
||||||
[ $((quote_count % 2)) -eq 0 ] || { printf 'Generated Codex config.toml has unbalanced quotes: %s\n' "$toml_path" >&2; exit 1; }
|
|
||||||
open_brackets=$(grep -o '\[' "$toml_path" | wc -l)
|
|
||||||
close_brackets=$(grep -o '\]' "$toml_path" | wc -l)
|
|
||||||
[ "$open_brackets" -eq "$close_brackets" ] || { printf 'Generated Codex config.toml has unbalanced brackets: %s\n' "$toml_path" >&2; exit 1; }
|
|
||||||
|
|
||||||
settings_path="$output/claude-$platform/settings.json"
|
settings_path="$output/claude-$platform/settings.json"
|
||||||
if command -v jq >/dev/null 2>&1; then
|
python3 "$root/scripts/validate-config.py" "$toml_path" "$settings_path"
|
||||||
jq empty "$settings_path" >/dev/null 2>&1 || { printf 'Generated Claude settings.json is not valid JSON: %s\n' "$settings_path" >&2; exit 1; }
|
if command -v codex >/dev/null; then
|
||||||
elif command -v python3 >/dev/null 2>&1 && python3 --version >/dev/null 2>&1; then
|
schema_home=$(mktemp -d)
|
||||||
# On Windows, `python3` can resolve to a non-functional Microsoft Store app-execution
|
cp "$toml_path" "$schema_home/config.toml"
|
||||||
# alias that still passes `command -v`; probe it with a real invocation before trusting it.
|
CODEX_HOME="$schema_home" codex --strict-config --help >/dev/null
|
||||||
python3 -c 'import json,sys; json.load(open(sys.argv[1], encoding="utf-8"))' "$settings_path" || { printf 'Generated Claude settings.json is not valid JSON: %s\n' "$settings_path" >&2; exit 1; }
|
rm -rf -- "$schema_home"
|
||||||
|
elif [ "${REQUIRE_CODEX_SCHEMA:-false}" = true ]; then
|
||||||
|
printf 'Codex CLI is required for schema validation.\n' >&2
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
printf 'WARN Codex CLI unavailable; skipped Codex schema validation.\n' >&2
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
+16
-3
@@ -42,9 +42,16 @@ if (Test-Path -LiteralPath $settingsPath) {
|
|||||||
}
|
}
|
||||||
$configTomlPath = Join-Path $homePath '.codex/config.toml'
|
$configTomlPath = Join-Path $homePath '.codex/config.toml'
|
||||||
if (Test-Path -LiteralPath $configTomlPath) {
|
if (Test-Path -LiteralPath $configTomlPath) {
|
||||||
$tomlContent = Get-Content -LiteralPath $configTomlPath -Raw
|
$parseResult = & python -c 'import sys,tomllib,pathlib; tomllib.loads(pathlib.Path(sys.argv[1]).read_text(encoding="utf-8-sig"))' $configTomlPath 2>&1
|
||||||
$balanced = (([regex]::Matches($tomlContent, '(?<!\\)"')).Count % 2 -eq 0) -and (([regex]::Matches($tomlContent, '\[')).Count -eq ([regex]::Matches($tomlContent, '\]')).Count)
|
if ($LASTEXITCODE -eq 0) { Result 'PASS' 'installed .codex/config.toml parses as TOML' } else { Result 'FAIL' "installed .codex/config.toml is invalid TOML: $parseResult" }
|
||||||
if ($balanced) { Result 'PASS' 'installed .codex/config.toml looks structurally valid' } else { Result 'FAIL' 'installed .codex/config.toml has unbalanced quotes or brackets' }
|
if (Get-Command codex -ErrorAction SilentlyContinue) {
|
||||||
|
$previousCodexHome = $env:CODEX_HOME
|
||||||
|
try {
|
||||||
|
$env:CODEX_HOME = Split-Path $configTomlPath -Parent
|
||||||
|
$schemaResult = & codex --strict-config --help 2>&1
|
||||||
|
if ($LASTEXITCODE -eq 0) { Result 'PASS' 'installed .codex/config.toml matches the installed Codex schema' } else { Result 'FAIL' "installed .codex/config.toml has unsupported Codex settings: $schemaResult" }
|
||||||
|
} finally { $env:CODEX_HOME = $previousCodexHome }
|
||||||
|
} else { Result 'WARN' 'Codex CLI unavailable; skipped installed Codex schema validation' }
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($destination in @((Join-Path $homePath '.codex'), (Join-Path $homePath '.agents/skills'), (Join-Path $homePath '.claude'))) {
|
foreach ($destination in @((Join-Path $homePath '.codex'), (Join-Path $homePath '.agents/skills'), (Join-Path $homePath '.claude'))) {
|
||||||
@@ -64,6 +71,12 @@ foreach ($destination in @((Join-Path $homePath '.codex'), (Join-Path $homePath
|
|||||||
|
|
||||||
foreach ($path in @('shared/rules','shared/skills','shared/agents','shared/hooks/scripts')) { if (Test-Path (Join-Path $root $path)) { Result 'PASS' "source $path" } else { Result 'FAIL' "missing $path" } }
|
foreach ($path in @('shared/rules','shared/skills','shared/agents','shared/hooks/scripts')) { if (Test-Path (Join-Path $root $path)) { Result 'PASS' "source $path" } else { Result 'FAIL' "missing $path" } }
|
||||||
|
|
||||||
|
foreach ($client in @('codex','claude')) {
|
||||||
|
$config = if ($client -eq 'codex') { Join-Path $root 'adapters/codex/config/config.toml' } else { Join-Path $root 'adapters/claude/config/settings.json' }
|
||||||
|
$registered = if ($client -eq 'codex') { (Get-Content $config -Raw) -match '\[\[hooks\.Stop\]\]' } else { ((Get-Content $config -Raw | ConvertFrom-Json).hooks.PSObject.Properties.Name -contains 'Stop') }
|
||||||
|
if ($registered) { Result 'PASS' "$client Stop hook is registered" } else { Result 'WARN' "$client ships hook utilities, but no Stop hook is registered" }
|
||||||
|
}
|
||||||
|
|
||||||
if ($fail) { exit 1 }
|
if ($fail) { exit 1 }
|
||||||
Write-Output 'PASS doctor'
|
Write-Output 'PASS doctor'
|
||||||
exit 0
|
exit 0
|
||||||
+6
-6
@@ -55,14 +55,14 @@ if [ -f "$home_path/.claude/settings.json" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if [ -f "$home_path/.codex/config.toml" ]; then
|
if [ -f "$home_path/.codex/config.toml" ]; then
|
||||||
quote_count=$(grep -o '"' "$home_path/.codex/config.toml" | wc -l)
|
if python3 -c 'import sys,tomllib,pathlib; tomllib.loads(pathlib.Path(sys.argv[1]).read_text(encoding="utf-8-sig"))' "$home_path/.codex/config.toml"; then
|
||||||
open_brackets=$(grep -o '\[' "$home_path/.codex/config.toml" | wc -l)
|
result PASS 'installed .codex/config.toml parses as TOML'
|
||||||
close_brackets=$(grep -o '\]' "$home_path/.codex/config.toml" | wc -l)
|
|
||||||
if [ $((quote_count % 2)) -eq 0 ] && [ "$open_brackets" -eq "$close_brackets" ]; then
|
|
||||||
result PASS 'installed .codex/config.toml looks structurally valid'
|
|
||||||
else
|
else
|
||||||
result FAIL 'installed .codex/config.toml has unbalanced quotes or brackets'
|
result FAIL 'installed .codex/config.toml is invalid TOML'
|
||||||
fi
|
fi
|
||||||
|
if command -v codex >/dev/null; then
|
||||||
|
if CODEX_HOME="$home_path/.codex" codex --strict-config --help >/dev/null 2>&1; then result PASS 'installed .codex/config.toml matches the installed Codex schema'; else result FAIL 'installed .codex/config.toml has unsupported Codex settings'; fi
|
||||||
|
else result WARN 'Codex CLI unavailable; skipped installed Codex schema validation'; fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for destination in "$home_path/.codex" "$home_path/.agents/skills" "$home_path/.claude"; do
|
for destination in "$home_path/.codex" "$home_path/.agents/skills" "$home_path/.claude"; do
|
||||||
|
|||||||
@@ -85,6 +85,20 @@ function Install-ConfiguredPlugins {
|
|||||||
$plugin = if ($selectedClient -eq 'Claude') { $entry.claude_plugin } else { $entry.codex_plugin }
|
$plugin = if ($selectedClient -eq 'Claude') { $entry.claude_plugin } else { $entry.codex_plugin }
|
||||||
if ([string]::IsNullOrWhiteSpace($plugin)) { throw ('Plugin selector missing for {0}: {1}' -f $selectedClient, $entry.name) }
|
if ([string]::IsNullOrWhiteSpace($plugin)) { throw ('Plugin selector missing for {0}: {1}' -f $selectedClient, $entry.name) }
|
||||||
|
|
||||||
|
if ($selectedClient -eq 'Codex' -and $entry.codex_method -ne 'plugin') {
|
||||||
|
if ($entry.codex_method -eq 'skill') {
|
||||||
|
$arguments = @('-y','skills','add',$entry.codex_source,'--global','--agent','codex')
|
||||||
|
if ($entry.codex_skill -ne '-') { $arguments = @('-y','skills','add',$entry.codex_source,'--skill',$entry.codex_skill,'--global','--agent','codex') }
|
||||||
|
} elseif ($entry.codex_method -eq 'impeccable') {
|
||||||
|
$arguments = @('-y','impeccable','install','-y','--providers=codex','--scope=global')
|
||||||
|
} else {
|
||||||
|
throw "Unknown Codex install method '$($entry.codex_method)' for $($entry.name)."
|
||||||
|
}
|
||||||
|
Invoke-PluginCommand -Command 'npx' -Arguments $arguments -DryRun:$DryRun
|
||||||
|
Write-Output "PASS Codex skill ensured: $($entry.name)"
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
$installedItem = if ($selectedClient -eq 'Claude') { $installed | Where-Object { $_.id -eq $plugin } | Select-Object -First 1 } else { $installed | Where-Object { $_.pluginId -eq $plugin } | Select-Object -First 1 }
|
$installedItem = if ($selectedClient -eq 'Claude') { $installed | Where-Object { $_.id -eq $plugin } | Select-Object -First 1 } else { $installed | Where-Object { $_.pluginId -eq $plugin } | Select-Object -First 1 }
|
||||||
if ($Update -and $selectedClient -eq 'Claude' -and $null -ne $installedItem) {
|
if ($Update -and $selectedClient -eq 'Claude' -and $null -ne $installedItem) {
|
||||||
Invoke-PluginCommand -Command 'claude' -Arguments @('plugin','update',$plugin) -DryRun:$DryRun
|
Invoke-PluginCommand -Command 'claude' -Arguments @('plugin','update',$plugin) -DryRun:$DryRun
|
||||||
|
|||||||
+19
-2
@@ -53,8 +53,8 @@ install_configured_plugins() {
|
|||||||
*) printf 'Unknown plugin client selection: %s\n' "$client_selection" >&2; return 1;;
|
*) printf 'Unknown plugin client selection: %s\n' "$client_selection" >&2; return 1;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
local client name claude_marketplace claude_plugin codex_marketplace codex_plugin marketplace plugin
|
local client name claude_marketplace claude_plugin codex_marketplace codex_plugin codex_method codex_source codex_skill marketplace plugin
|
||||||
while IFS=$'\t' read -r name claude_marketplace claude_plugin codex_marketplace codex_plugin; do
|
while IFS=$'\t' read -r name claude_marketplace claude_plugin codex_marketplace codex_plugin codex_method codex_source codex_skill; do
|
||||||
[ "$name" = name ] && continue
|
[ "$name" = name ] && continue
|
||||||
[ -n "$name" ] || continue
|
[ -n "$name" ] || continue
|
||||||
[ "$claude_marketplace" = - ] && claude_marketplace=
|
[ "$claude_marketplace" = - ] && claude_marketplace=
|
||||||
@@ -62,6 +62,23 @@ install_configured_plugins() {
|
|||||||
for client in "${clients[@]}"; do
|
for client in "${clients[@]}"; do
|
||||||
if [ "$client" = claude ]; then marketplace=$claude_marketplace; plugin=$claude_plugin; else marketplace=$codex_marketplace; plugin=$codex_plugin; fi
|
if [ "$client" = claude ]; then marketplace=$claude_marketplace; plugin=$claude_plugin; else marketplace=$codex_marketplace; plugin=$codex_plugin; fi
|
||||||
[ -n "$plugin" ] || { printf 'Plugin selector missing for %s: %s\n' "$client" "$name" >&2; return 1; }
|
[ -n "$plugin" ] || { printf 'Plugin selector missing for %s: %s\n' "$client" "$name" >&2; return 1; }
|
||||||
|
if [ "$client" = codex ] && [ "$codex_method" != plugin ]; then
|
||||||
|
case "$codex_method" in
|
||||||
|
skill)
|
||||||
|
if [ "$codex_skill" = - ]; then
|
||||||
|
run_plugin_command "$dry_run" npx -y skills add "$codex_source" --global --agent codex
|
||||||
|
else
|
||||||
|
run_plugin_command "$dry_run" npx -y skills add "$codex_source" --skill "$codex_skill" --global --agent codex
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
impeccable)
|
||||||
|
run_plugin_command "$dry_run" npx -y impeccable install -y --providers=codex --scope=global
|
||||||
|
;;
|
||||||
|
*) printf 'Unknown Codex install method for %s: %s\n' "$client" "$name" >&2; return 1;;
|
||||||
|
esac
|
||||||
|
printf 'PASS Codex skill ensured: %s\n' "$name"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
if [ "$dry_run" = false ] && plugin_installed "$client" "$plugin"; then
|
if [ "$dry_run" = false ] && plugin_installed "$client" "$plugin"; then
|
||||||
if [ "$update" = true ] && [ "$client" = claude ]; then
|
if [ "$update" = true ] && [ "$client" = claude ]; then
|
||||||
run_plugin_command "$dry_run" claude plugin update "$plugin"
|
run_plugin_command "$dry_run" claude plugin update "$plugin"
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Validate the generated configuration formats without third-party packages."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import tomllib
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
CLAUDE_TOP_LEVEL = {"permissions", "env", "statusLine", "hooks"}
|
||||||
|
CLAUDE_PERMISSION_KEYS = {"defaultMode", "allow", "deny"}
|
||||||
|
CLAUDE_STATUS_LINE_KEYS = {"type", "command"}
|
||||||
|
CLAUDE_HOOK_KEYS = {"type", "command", "timeout"}
|
||||||
|
CLAUDE_PERMISSION_MODES = {"acceptEdits", "auto", "bypassPermissions", "default", "dontAsk", "plan"}
|
||||||
|
|
||||||
|
|
||||||
|
def fail(message: str) -> None:
|
||||||
|
raise ValueError(message)
|
||||||
|
|
||||||
|
|
||||||
|
def require_keys(value: object, allowed: set[str], label: str) -> dict[str, object]:
|
||||||
|
if not isinstance(value, dict):
|
||||||
|
fail(f"{label} must be an object")
|
||||||
|
unknown = set(value) - allowed
|
||||||
|
if unknown:
|
||||||
|
fail(f"{label} has unknown keys: {', '.join(sorted(unknown))}")
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def validate_claude(path: Path) -> None:
|
||||||
|
settings = require_keys(json.loads(path.read_text(encoding="utf-8-sig")), CLAUDE_TOP_LEVEL, str(path))
|
||||||
|
permissions = require_keys(settings.get("permissions"), CLAUDE_PERMISSION_KEYS, "permissions")
|
||||||
|
if permissions.get("defaultMode") not in CLAUDE_PERMISSION_MODES:
|
||||||
|
fail("permissions.defaultMode is unsupported")
|
||||||
|
for key in ("allow", "deny"):
|
||||||
|
if not isinstance(permissions.get(key), list) or not all(isinstance(item, str) for item in permissions[key]):
|
||||||
|
fail(f"permissions.{key} must be an array of strings")
|
||||||
|
env = settings.get("env")
|
||||||
|
if not isinstance(env, dict) or not all(isinstance(key, str) and isinstance(value, str) for key, value in env.items()):
|
||||||
|
fail("env must be an object of string values")
|
||||||
|
status_line = require_keys(settings.get("statusLine"), CLAUDE_STATUS_LINE_KEYS, "statusLine")
|
||||||
|
if status_line.get("type") != "command" or not isinstance(status_line.get("command"), str):
|
||||||
|
fail("statusLine must be a command")
|
||||||
|
hooks = settings.get("hooks")
|
||||||
|
if not isinstance(hooks, dict):
|
||||||
|
fail("hooks must be an object")
|
||||||
|
for event, matchers in hooks.items():
|
||||||
|
if not isinstance(event, str) or not isinstance(matchers, list):
|
||||||
|
fail("hooks must map event names to arrays")
|
||||||
|
for matcher in matchers:
|
||||||
|
if not isinstance(matcher, dict) or not isinstance(matcher.get("hooks"), list):
|
||||||
|
fail(f"hooks.{event} must contain hook arrays")
|
||||||
|
for hook in matcher["hooks"]:
|
||||||
|
hook = require_keys(hook, CLAUDE_HOOK_KEYS, f"hooks.{event}")
|
||||||
|
if hook.get("type") != "command" or not isinstance(hook.get("command"), str) or not isinstance(hook.get("timeout"), int):
|
||||||
|
fail(f"hooks.{event} contains an unsupported command hook")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print("usage: validate-config.py <codex-toml> <claude-json>", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
tomllib.loads(Path(sys.argv[1]).read_text(encoding="utf-8-sig"))
|
||||||
|
validate_claude(Path(sys.argv[2]))
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
raise SystemExit(main())
|
||||||
|
except (OSError, ValueError, json.JSONDecodeError, tomllib.TOMLDecodeError) as error:
|
||||||
|
print(f"configuration validation failed: {error}", file=sys.stderr)
|
||||||
|
raise SystemExit(1)
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
name: architect
|
name: architect
|
||||||
description: Technical architecture and design
|
description: Technical architecture and design
|
||||||
role: architect
|
role: architect
|
||||||
write_permissions: read-only by default
|
|
||||||
capabilities: boundaries, dependencies, interfaces, trade-offs, constraints, technical options
|
|
||||||
delegation: ask the user about business behavior, user experience, APIs, data models, or configuration formats when certainty is incomplete
|
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
name: implementer
|
name: implementer
|
||||||
description: Execute engineering work
|
description: Execute engineering work
|
||||||
role: implementer
|
role: implementer
|
||||||
write_permissions: modify in the user-authorized workspace; ask before external writes
|
|
||||||
capabilities: requirements analysis, implementation, verification, self-review
|
|
||||||
delegation: use researcher, architect, reviewer, or verifier when their independent work is useful
|
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
name: researcher
|
name: researcher
|
||||||
description: Repository and technical investigation
|
description: Repository and technical investigation
|
||||||
role: researcher
|
role: researcher
|
||||||
write_permissions: read-only by default
|
|
||||||
capabilities: repository inspection, pattern discovery, evidence gathering, approach comparison, unknown identification
|
|
||||||
delegation: summarize findings before implementation when useful
|
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
name: reviewer
|
name: reviewer
|
||||||
description: Independent quality review
|
description: Independent quality review
|
||||||
role: reviewer
|
role: reviewer
|
||||||
write_permissions: read-only by default
|
|
||||||
capabilities: correctness, regressions, security, maintainability, architecture, tests, complexity
|
|
||||||
delegation: review independently; do not blindly trust implementation claims
|
|
||||||
@@ -1,6 +1,3 @@
|
|||||||
name: verifier
|
name: verifier
|
||||||
description: Focused verification of completed work
|
description: Focused verification of completed work
|
||||||
role: verifier
|
role: verifier
|
||||||
write_permissions: read-only by default
|
|
||||||
capabilities: acceptance criteria, tests, regressions, generated output, configuration, evidence
|
|
||||||
delegation: verify the requested scope independently and report evidence and remaining uncertainty
|
|
||||||
@@ -12,4 +12,4 @@ Never modify existing documentation automatically. Ask before a code change that
|
|||||||
|
|
||||||
Project-specific instructions may specialize global defaults but must not weaken security or data-loss protections without explicit user approval. Direct user instructions have the highest priority for requested behavior.
|
Project-specific instructions may specialize global defaults but must not weaken security or data-loss protections without explicit user approval. Direct user instructions have the highest priority for requested behavior.
|
||||||
|
|
||||||
Use implementer for execution and architect when technical boundaries or design options need dedicated analysis. Invoke researcher, reviewer, or verifier only when independent work is likely to improve the outcome. Decide based on uncertainty, complexity, risk, blast radius, and verification value; do not invoke these roles automatically. Parallelize only genuinely independent work.
|
Use one implementer for small, contained tasks. Add researcher only for material uncertainty, architect only for architecture or boundary decisions, reviewer only for independent quality review, and verifier only for explicit acceptance criteria, tests, or generated artifacts. Do not start reviewer and verifier by default or let subagents create further subagents. Parallelize only genuinely independent work.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# API security
|
||||||
|
|
||||||
|
* Authenticate and authorize protected endpoints; validate every request payload and identifier.
|
||||||
|
* Bound request and response sizes, pagination, query results, and expensive operations.
|
||||||
|
* Apply rate limits where abuse is plausible and keep administrative endpoints separately protected.
|
||||||
|
* Return only authorized data and never expose stack traces, internal models, or implementation details in API errors.
|
||||||
|
* Prefer explicit DTOs and schemas over deserializing arbitrary types or executable objects.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# Authentication and authorization security
|
||||||
|
|
||||||
|
* Use established authentication standards and password hashing; never store plaintext or reversibly encrypted passwords.
|
||||||
|
* Enforce authorization server-side for every sensitive operation and verify resource ownership and tenant boundaries.
|
||||||
|
* Use least-privilege roles, short-lived sessions or tokens where supported, and invalidate credentials after sensitive account changes.
|
||||||
|
* Validate token issuer, audience, signature, and expiry before trusting claims.
|
||||||
|
* Protect authentication and privileged actions against brute force and privilege escalation.
|
||||||
|
* Test unauthenticated, unauthorized, cross-user, and cross-tenant access paths.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Cryptography and secrets security
|
||||||
|
|
||||||
|
* Never implement custom cryptographic primitives or use obsolete algorithms.
|
||||||
|
* Use established libraries, authenticated encryption, secure randomness, and verified signatures and certificates.
|
||||||
|
* Treat tokens, private keys, connection strings, and credentials as secrets; keep them out of source, URLs, command lines, logs, fixtures, and frontend code.
|
||||||
|
* Use environment-appropriate secret storage, separate environments, and rotate compromised credentials.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Database and data security
|
||||||
|
|
||||||
|
* Use parameterized queries or ORM parameter binding; never concatenate untrusted input into SQL.
|
||||||
|
* Use least-privilege database accounts and protect connection strings.
|
||||||
|
* Scope tenant-owned queries explicitly and prevent cross-tenant cache, logging, and diagnostic leakage.
|
||||||
|
* Collect and retain only necessary sensitive data; encrypt it in transit and at rest where appropriate.
|
||||||
|
* Avoid raw database errors and use transactions where integrity requires atomicity.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# File and process security
|
||||||
|
|
||||||
|
* Validate filenames, content, sizes, and paths; prevent traversal, zip-slip, and unsafe symbolic-link use.
|
||||||
|
* Restrict access to intended directories and do not execute uploaded or untrusted files.
|
||||||
|
* Do not concatenate untrusted input into shell commands; prefer direct APIs and validate process arguments when execution is required.
|
||||||
|
* Treat local files, IPC, and deserialized input as untrusted at relevant boundaries.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Network and SSRF security
|
||||||
|
|
||||||
|
* Use HTTPS and never disable certificate or TLS validation.
|
||||||
|
* Restrict inbound and outbound access to required ports, interfaces, hosts, and protocols.
|
||||||
|
* Treat user-controlled URLs as dangerous: allowlist schemes and hosts, block localhost, metadata, and internal ranges, and revalidate redirects.
|
||||||
|
* Set timeouts, response-size limits, bounded retries, and cancellation for remote operations.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# Supply-chain security
|
||||||
|
|
||||||
|
* Keep dependencies minimal, maintained, and from verified sources; respect lockfiles and review identity and compatibility before adding or upgrading packages.
|
||||||
|
* Pin versions where appropriate and remove unused dependencies.
|
||||||
|
* Treat plugins, build scripts, CI actions, and generated artifacts as part of the attack surface.
|
||||||
|
* Use least privilege for build and deployment identities and never expose credentials in pipelines, logs, or artifacts.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Web and frontend security
|
||||||
|
|
||||||
|
* Escape or sanitize untrusted content; never inject untrusted HTML or bypass framework sanitization.
|
||||||
|
* Protect state-changing browser requests from CSRF where applicable.
|
||||||
|
* Use `HttpOnly`, `Secure`, and appropriate `SameSite` cookie settings for sensitive sessions.
|
||||||
|
* Validate redirect targets, avoid sensitive data in URLs, and use CSP and clickjacking protections where applicable.
|
||||||
|
* Treat frontend code and browser storage as visible and never rely on client-side checks for authorization.
|
||||||
+9
-402
@@ -1,404 +1,11 @@
|
|||||||
# Security Guidelines
|
# Security baseline
|
||||||
|
|
||||||
Security is a default requirement for all code, architecture, configuration and infrastructure changes.
|
Apply this baseline to every code, configuration, infrastructure, or review task.
|
||||||
|
|
||||||
## Core Principles
|
* Treat external input as untrusted and validate at trust boundaries.
|
||||||
|
* Prefer secure defaults, least privilege, explicit authorization, and fail-closed behavior.
|
||||||
* Prefer secure defaults.
|
* Never hardcode, commit, log, expose, or weaken protections for secrets and credentials.
|
||||||
* Apply least privilege everywhere.
|
* Use established framework and platform security mechanisms; do not invent cryptography or bypass validation, authentication, authorization, or TLS checks.
|
||||||
* Minimize exposed attack surface.
|
* Keep dependencies minimal and from trusted sources.
|
||||||
* Treat all external input as untrusted.
|
* Do not disclose sensitive data or internal implementation details in user-facing errors or diagnostics.
|
||||||
* Never trust client-side validation alone.
|
* Load the applicable focused security rule before changing authentication, web/UI, APIs, databases, files, network access, cryptography, secrets, or supply-chain configuration.
|
||||||
* Fail securely.
|
|
||||||
* Prefer deny-by-default over allow-by-default for sensitive operations.
|
|
||||||
* Keep security controls explicit and auditable.
|
|
||||||
* Do not weaken security for convenience.
|
|
||||||
* Do not bypass security mechanisms to make code easier to implement.
|
|
||||||
* Do not introduce insecure temporary solutions.
|
|
||||||
* Prefer simple, well-understood security mechanisms over custom cryptography or clever security logic.
|
|
||||||
|
|
||||||
## Secrets and Credentials
|
|
||||||
|
|
||||||
* Never hardcode passwords, API keys, tokens, connection strings, private keys or secrets.
|
|
||||||
* Never commit secrets to source control.
|
|
||||||
* Never log secrets or credentials.
|
|
||||||
* Never expose secrets in exceptions, diagnostics or UI messages.
|
|
||||||
* Use secure secret storage appropriate to the environment.
|
|
||||||
* Prefer short-lived credentials where supported.
|
|
||||||
* Rotate compromised credentials immediately.
|
|
||||||
* Do not reuse credentials across environments.
|
|
||||||
* Keep development, staging and production credentials separate.
|
|
||||||
* Avoid secrets in URLs, query strings or command-line arguments.
|
|
||||||
* Do not store secrets in frontend code.
|
|
||||||
* Do not include real credentials in examples, tests or fixtures.
|
|
||||||
|
|
||||||
## Authentication
|
|
||||||
|
|
||||||
* Use established authentication standards and framework capabilities.
|
|
||||||
* Do not implement custom authentication protocols without a strong reason.
|
|
||||||
* Store passwords only using modern password hashing algorithms designed for password storage.
|
|
||||||
* Never store plaintext passwords.
|
|
||||||
* Never use reversible encryption for password storage.
|
|
||||||
* Support secure session expiration.
|
|
||||||
* Invalidate sessions or tokens when security-sensitive account state changes.
|
|
||||||
* Protect authentication endpoints against brute-force abuse where applicable.
|
|
||||||
* Avoid exposing whether an account exists unless required.
|
|
||||||
* Require stronger authentication for security-sensitive actions where appropriate.
|
|
||||||
|
|
||||||
## Authorization
|
|
||||||
|
|
||||||
* Enforce authorization on the server side.
|
|
||||||
* Never rely on hidden UI elements, disabled buttons or frontend guards as authorization.
|
|
||||||
* Check authorization for every sensitive operation.
|
|
||||||
* Prefer explicit permission checks.
|
|
||||||
* Use least-privilege roles and permissions.
|
|
||||||
* Avoid broad administrative permissions unless required.
|
|
||||||
* Prevent horizontal privilege escalation between users or tenants.
|
|
||||||
* Prevent vertical privilege escalation between permission levels.
|
|
||||||
* Verify ownership of resources before access or modification.
|
|
||||||
* Do not trust identifiers supplied by the client as proof of authorization.
|
|
||||||
|
|
||||||
## Input Validation
|
|
||||||
|
|
||||||
* Validate all input from users, APIs, files, databases, queues, environment variables and external systems.
|
|
||||||
* Validate type, length, range, format and allowed values.
|
|
||||||
* Prefer allowlists over denylists.
|
|
||||||
* Reject unexpected input.
|
|
||||||
* Normalize input before validation when appropriate.
|
|
||||||
* Do not rely solely on client-side validation.
|
|
||||||
* Validate identifiers before using them for resource access.
|
|
||||||
* Validate uploaded files by content, size and expected type where applicable.
|
|
||||||
* Do not trust file extensions alone.
|
|
||||||
|
|
||||||
## Injection Prevention
|
|
||||||
|
|
||||||
* Never concatenate untrusted input into SQL.
|
|
||||||
* Use parameterized queries or ORM parameter binding.
|
|
||||||
* Never concatenate untrusted input into shell commands.
|
|
||||||
* Avoid executing shell commands when a direct API is available.
|
|
||||||
* Validate and escape command arguments when process execution is required.
|
|
||||||
* Prevent LDAP, XPath, template and expression injection where applicable.
|
|
||||||
* Avoid dynamic code execution.
|
|
||||||
* Avoid `eval`, dynamic compilation and equivalent mechanisms unless strictly required.
|
|
||||||
* Treat template engines and interpreters as security boundaries.
|
|
||||||
|
|
||||||
## Web Security
|
|
||||||
|
|
||||||
* Prevent Cross-Site Scripting by using framework escaping and sanitization.
|
|
||||||
* Never inject untrusted HTML directly.
|
|
||||||
* Avoid bypassing framework sanitization.
|
|
||||||
* Protect state-changing browser requests against CSRF where applicable.
|
|
||||||
* Use secure cookies for sensitive session data.
|
|
||||||
* Use `HttpOnly` for authentication cookies where possible.
|
|
||||||
* Use `Secure` cookies in HTTPS environments.
|
|
||||||
* Configure `SameSite` appropriately.
|
|
||||||
* Use appropriate Content Security Policy where applicable.
|
|
||||||
* Avoid leaking sensitive data through referrers or URLs.
|
|
||||||
* Validate redirect targets to prevent open redirects.
|
|
||||||
* Protect against clickjacking where applicable.
|
|
||||||
|
|
||||||
## API Security
|
|
||||||
|
|
||||||
* Authenticate sensitive endpoints.
|
|
||||||
* Authorize every protected operation.
|
|
||||||
* Validate all request payloads.
|
|
||||||
* Apply reasonable request-size limits.
|
|
||||||
* Apply pagination and bounded queries.
|
|
||||||
* Apply rate limiting where abuse is possible.
|
|
||||||
* Avoid exposing internal models directly when this leaks implementation details.
|
|
||||||
* Return only data the caller is authorized to access.
|
|
||||||
* Do not expose stack traces or internal exception details.
|
|
||||||
* Avoid excessive information in error responses.
|
|
||||||
* Version public APIs intentionally.
|
|
||||||
* Protect administrative endpoints separately where appropriate.
|
|
||||||
|
|
||||||
## Data Protection
|
|
||||||
|
|
||||||
* Collect only data that is actually required.
|
|
||||||
* Minimize storage of sensitive data.
|
|
||||||
* Classify sensitive data explicitly.
|
|
||||||
* Encrypt sensitive data in transit.
|
|
||||||
* Encrypt sensitive data at rest where appropriate.
|
|
||||||
* Do not implement custom encryption algorithms.
|
|
||||||
* Use established cryptographic libraries.
|
|
||||||
* Do not use obsolete cryptographic algorithms.
|
|
||||||
* Do not use hardcoded encryption keys.
|
|
||||||
* Use cryptographically secure random number generation for security-sensitive values.
|
|
||||||
* Avoid exposing personal or sensitive data in logs.
|
|
||||||
* Delete sensitive data when it is no longer required.
|
|
||||||
|
|
||||||
## Cryptography
|
|
||||||
|
|
||||||
* Never design custom cryptographic primitives.
|
|
||||||
* Use current, established cryptographic standards.
|
|
||||||
* Use authenticated encryption when confidentiality and integrity are required.
|
|
||||||
* Verify signatures before trusting signed content.
|
|
||||||
* Validate certificates correctly.
|
|
||||||
* Never disable certificate validation.
|
|
||||||
* Never accept all TLS certificates.
|
|
||||||
* Do not downgrade TLS security.
|
|
||||||
* Use secure randomness for tokens, nonces, identifiers and keys.
|
|
||||||
* Never use predictable random generators for security-sensitive values.
|
|
||||||
|
|
||||||
## Tokens and Sessions
|
|
||||||
|
|
||||||
* Treat tokens as secrets.
|
|
||||||
* Keep token lifetime as short as practical.
|
|
||||||
* Validate issuer, audience, signature and expiration where applicable.
|
|
||||||
* Do not accept unsigned tokens unless explicitly designed and safe.
|
|
||||||
* Do not trust token contents before validation.
|
|
||||||
* Avoid storing long-lived access tokens in insecure browser storage.
|
|
||||||
* Rotate refresh tokens where appropriate.
|
|
||||||
* Revoke compromised tokens where possible.
|
|
||||||
* Prevent replay attacks where the protocol requires it.
|
|
||||||
|
|
||||||
## File Security
|
|
||||||
|
|
||||||
* Validate file names and paths.
|
|
||||||
* Prevent path traversal.
|
|
||||||
* Never concatenate untrusted input directly into filesystem paths.
|
|
||||||
* Restrict file access to intended directories.
|
|
||||||
* Use generated server-side file names where appropriate.
|
|
||||||
* Enforce file size limits.
|
|
||||||
* Validate uploaded content.
|
|
||||||
* Do not execute uploaded files.
|
|
||||||
* Store uploads outside executable web roots where applicable.
|
|
||||||
* Handle archive extraction safely.
|
|
||||||
* Prevent zip-slip and equivalent path traversal attacks.
|
|
||||||
* Avoid following untrusted symbolic links where security-sensitive.
|
|
||||||
|
|
||||||
## Serialization
|
|
||||||
|
|
||||||
* Treat deserialized input as untrusted.
|
|
||||||
* Avoid insecure polymorphic deserialization.
|
|
||||||
* Avoid deserializing arbitrary runtime types.
|
|
||||||
* Use explicit schemas or known DTOs.
|
|
||||||
* Restrict type resolution.
|
|
||||||
* Do not deserialize executable objects or behavior.
|
|
||||||
* Validate deserialized data before use.
|
|
||||||
* Avoid insecure legacy serializers.
|
|
||||||
|
|
||||||
## Database Security
|
|
||||||
|
|
||||||
* Use parameterized queries.
|
|
||||||
* Use least-privilege database accounts.
|
|
||||||
* Do not use administrative database accounts for normal application traffic.
|
|
||||||
* Restrict schema modification permissions in runtime accounts.
|
|
||||||
* Protect connection strings.
|
|
||||||
* Avoid exposing raw database errors.
|
|
||||||
* Limit query size and result sets.
|
|
||||||
* Prevent tenant data leakage.
|
|
||||||
* Verify tenant boundaries in every relevant query.
|
|
||||||
* Use transactions where integrity requires atomicity.
|
|
||||||
|
|
||||||
## Logging and Monitoring
|
|
||||||
|
|
||||||
* Never log secrets.
|
|
||||||
* Never log passwords.
|
|
||||||
* Never log authentication tokens.
|
|
||||||
* Avoid logging sensitive personal data.
|
|
||||||
* Use structured logging.
|
|
||||||
* Include security-relevant context without exposing sensitive values.
|
|
||||||
* Log authentication and authorization failures where appropriate.
|
|
||||||
* Log suspicious or high-risk actions where appropriate.
|
|
||||||
* Avoid log injection by treating user input as data.
|
|
||||||
* Do not let logging failures break critical application behavior.
|
|
||||||
* Ensure logs have appropriate access controls.
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
* Fail securely.
|
|
||||||
* Do not expose internal stack traces to users.
|
|
||||||
* Do not reveal implementation details unnecessarily.
|
|
||||||
* Preserve diagnostic detail internally where safe.
|
|
||||||
* Avoid different error responses that reveal sensitive existence checks where not required.
|
|
||||||
* Do not swallow security-relevant exceptions.
|
|
||||||
* Do not continue execution after critical validation or authorization failures.
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
* Keep dependencies minimal.
|
|
||||||
* Prefer maintained and widely used packages.
|
|
||||||
* Avoid abandoned packages.
|
|
||||||
* Avoid unnecessary dependencies for trivial functionality.
|
|
||||||
* Keep dependencies updated with security patches.
|
|
||||||
* Review dependency changes before adoption.
|
|
||||||
* Do not blindly update major versions without compatibility review.
|
|
||||||
* Remove unused dependencies.
|
|
||||||
* Treat transitive dependencies as part of the attack surface.
|
|
||||||
* Verify package identity before installation.
|
|
||||||
* Avoid untrusted package sources.
|
|
||||||
* Respect lockfiles.
|
|
||||||
|
|
||||||
## Supply Chain Security
|
|
||||||
|
|
||||||
* Pin dependency versions where appropriate.
|
|
||||||
* Protect build and deployment pipelines.
|
|
||||||
* Do not expose CI/CD credentials.
|
|
||||||
* Use least privilege for pipeline identities.
|
|
||||||
* Review third-party actions, plugins and build scripts.
|
|
||||||
* Avoid executing untrusted build scripts.
|
|
||||||
* Verify artifacts and sources where practical.
|
|
||||||
* Keep generated artifacts traceable to source.
|
|
||||||
* Do not publish secrets in build logs or artifacts.
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
* Use secure production defaults.
|
|
||||||
* Do not enable debug mode in production.
|
|
||||||
* Do not expose development endpoints in production.
|
|
||||||
* Separate environment-specific configuration.
|
|
||||||
* Validate security-sensitive configuration at startup.
|
|
||||||
* Fail startup when mandatory security configuration is missing.
|
|
||||||
* Do not silently fall back to insecure settings.
|
|
||||||
* Protect configuration files containing sensitive values.
|
|
||||||
|
|
||||||
## Network Security
|
|
||||||
|
|
||||||
* Use HTTPS for sensitive or authenticated communication.
|
|
||||||
* Do not disable TLS validation.
|
|
||||||
* Restrict outbound network access where practical.
|
|
||||||
* Restrict inbound services to required ports and interfaces.
|
|
||||||
* Use timeouts for network operations.
|
|
||||||
* Limit retries to avoid amplification or denial-of-service behavior.
|
|
||||||
* Validate remote endpoints where SSRF is possible.
|
|
||||||
* Do not allow arbitrary user-controlled URLs for privileged server-side requests.
|
|
||||||
* Block access to internal network ranges when handling untrusted remote URLs where applicable.
|
|
||||||
|
|
||||||
## SSRF Prevention
|
|
||||||
|
|
||||||
* Treat user-controlled URLs as dangerous.
|
|
||||||
* Validate schemes.
|
|
||||||
* Prefer allowlisted hosts.
|
|
||||||
* Resolve and verify target addresses where necessary.
|
|
||||||
* Prevent access to localhost, metadata endpoints and internal networks where not explicitly required.
|
|
||||||
* Revalidate after redirects.
|
|
||||||
* Limit redirects.
|
|
||||||
* Apply request timeouts and response-size limits.
|
|
||||||
|
|
||||||
## Concurrency and Resource Abuse
|
|
||||||
|
|
||||||
* Bound concurrency.
|
|
||||||
* Avoid unbounded task creation.
|
|
||||||
* Avoid unbounded queues.
|
|
||||||
* Limit request sizes.
|
|
||||||
* Limit collection sizes when processing external input.
|
|
||||||
* Apply timeouts to external operations.
|
|
||||||
* Apply cancellation where practical.
|
|
||||||
* Prevent expensive operations from being triggered repeatedly without limits.
|
|
||||||
* Protect endpoints against denial-of-service through algorithmic complexity.
|
|
||||||
* Avoid user-controlled regular expressions that may cause catastrophic backtracking.
|
|
||||||
|
|
||||||
## Memory Safety and Resource Management
|
|
||||||
|
|
||||||
* Dispose files, streams, sockets and other resources correctly.
|
|
||||||
* Prevent resource leaks.
|
|
||||||
* Avoid retaining sensitive data in memory longer than necessary.
|
|
||||||
* Avoid unsafe code unless explicitly required.
|
|
||||||
* Review pointer and memory operations carefully.
|
|
||||||
* Avoid exposing raw memory or buffers across trust boundaries.
|
|
||||||
* Clear sensitive buffers where warranted.
|
|
||||||
|
|
||||||
## Multi-Tenant Systems
|
|
||||||
|
|
||||||
* Treat tenant boundaries as security boundaries.
|
|
||||||
* Scope every tenant-owned query explicitly.
|
|
||||||
* Never trust tenant identifiers from the client without authorization.
|
|
||||||
* Prevent cross-tenant cache leakage.
|
|
||||||
* Prevent cross-tenant logging or diagnostics leakage.
|
|
||||||
* Keep tenant-specific secrets isolated.
|
|
||||||
* Test horizontal privilege escalation explicitly.
|
|
||||||
|
|
||||||
## Frontend Security
|
|
||||||
|
|
||||||
* Assume frontend code and data are visible to the user.
|
|
||||||
* Never embed secrets in frontend applications.
|
|
||||||
* Never rely on frontend checks for authorization.
|
|
||||||
* Treat browser storage as potentially accessible to malicious scripts.
|
|
||||||
* Avoid storing sensitive long-lived tokens unnecessarily.
|
|
||||||
* Escape or sanitize untrusted content.
|
|
||||||
* Do not bypass framework security controls without explicit justification.
|
|
||||||
|
|
||||||
## Desktop Application Security
|
|
||||||
|
|
||||||
* Treat local files and IPC input as untrusted where applicable.
|
|
||||||
* Do not assume local users or processes are trusted.
|
|
||||||
* Avoid storing secrets in plaintext configuration.
|
|
||||||
* Protect locally cached sensitive data.
|
|
||||||
* Validate update packages and downloaded executables.
|
|
||||||
* Do not execute arbitrary files or commands from untrusted input.
|
|
||||||
* Use least privilege and avoid unnecessary elevation.
|
|
||||||
|
|
||||||
## Security-Sensitive Changes
|
|
||||||
|
|
||||||
Changes affecting any of the following require additional scrutiny:
|
|
||||||
|
|
||||||
* Authentication
|
|
||||||
* Authorization
|
|
||||||
* Cryptography
|
|
||||||
* Secrets
|
|
||||||
* User permissions
|
|
||||||
* File access
|
|
||||||
* Process execution
|
|
||||||
* Network access
|
|
||||||
* Input validation
|
|
||||||
* Serialization
|
|
||||||
* Database access
|
|
||||||
* Payment or financial data
|
|
||||||
* Personal or confidential data
|
|
||||||
* Admin functionality
|
|
||||||
* Deployment or infrastructure security
|
|
||||||
|
|
||||||
For security-sensitive changes:
|
|
||||||
|
|
||||||
* Prefer established framework functionality.
|
|
||||||
* Review trust boundaries.
|
|
||||||
* Review failure behavior.
|
|
||||||
* Review privilege requirements.
|
|
||||||
* Review input validation.
|
|
||||||
* Review logging for data leakage.
|
|
||||||
* Review backward compatibility for security implications.
|
|
||||||
* Add or update relevant security tests.
|
|
||||||
|
|
||||||
## Security Testing
|
|
||||||
|
|
||||||
* Test authorization failures.
|
|
||||||
* Test invalid and malicious input.
|
|
||||||
* Test boundary values.
|
|
||||||
* Test unauthenticated access.
|
|
||||||
* Test unauthorized resource access.
|
|
||||||
* Test cross-user and cross-tenant access where applicable.
|
|
||||||
* Test expired and invalid credentials.
|
|
||||||
* Test malformed payloads.
|
|
||||||
* Test path traversal where files are involved.
|
|
||||||
* Test injection risks where interpreters or databases are involved.
|
|
||||||
* Test rate and resource limits where abuse is realistic.
|
|
||||||
* Preserve regression tests for discovered security issues.
|
|
||||||
|
|
||||||
## Agent Rules
|
|
||||||
|
|
||||||
* Never intentionally weaken security controls without explicit user instruction.
|
|
||||||
* Never disable certificate validation, authentication, authorization, validation or security middleware to solve a problem.
|
|
||||||
* Never add hardcoded secrets.
|
|
||||||
* Never expose sensitive data for debugging convenience.
|
|
||||||
* Never bypass a security check because it blocks implementation.
|
|
||||||
* Never assume trusted input without a clearly defined trust boundary.
|
|
||||||
* Never silently choose a less secure implementation because it is easier.
|
|
||||||
* If a requested change creates a meaningful security risk, clearly identify the risk before proceeding.
|
|
||||||
* If requirements are ambiguous in a security-sensitive area, ask the user instead of making an autonomous security decision.
|
|
||||||
|
|
||||||
## Priority Order
|
|
||||||
|
|
||||||
Prioritize security decisions in this order:
|
|
||||||
|
|
||||||
* Prevent unauthorized access
|
|
||||||
* Protect sensitive data
|
|
||||||
* Preserve integrity
|
|
||||||
* Minimize privileges
|
|
||||||
* Minimize attack surface
|
|
||||||
* Validate trust boundaries
|
|
||||||
* Maintain availability
|
|
||||||
* Preserve auditability
|
|
||||||
* Optimize usability and performance only within acceptable security constraints
|
|
||||||
|
|
||||||
Security must not be traded away for convenience without an explicit and informed decision.
|
|
||||||
Reference in new issue
Block a user