chore(agents): implement v2 hardening and enforcement-ready QA

This commit is contained in:
2026-04-01 19:41:56 +02:00
parent 7121732fcf
commit dba589b495
31 changed files with 1349 additions and 78 deletions

View File

@@ -10,6 +10,7 @@ contracts/ ← JSON schemas for role outputs (7 roles)
templates/ ← Starter JSON payloads per role (7 templates)
prompts/ ← Role-specific prompt baselines (7 prompts)
checks/ ← Guard catalog (22 guards), quality gates (9), checklists
← Enforcement policy + guard enforcement map
skills/ ← Reusable skill packages (guardrails, planner, grid, PHP CI)
runs/ ← Runtime artifacts per workflow run (gitignored)
```
@@ -33,6 +34,8 @@ runs/ ← Runtime artifacts per workflow run (gitignored)
| Workflow & roles | `workflow.md` |
| Guard catalog (22 guards) | `checks/guard-catalog.json` |
| Quality gates (9 gates) | `checks/quality-gates.json` |
| Enforcement policy | `checks/enforcement-policy.json` |
| Guard enforcement map | `checks/guard-enforcement-map.json` |
| Code review checklist | `checks/guard-checklist.md` |
| Acceptance checklist | `checks/acceptance-checklist.md` |
| Module manifest schema | `contracts/module-manifest.schema.json` |

View File

@@ -0,0 +1,77 @@
{
"version": "1.0.0",
"phase": "enforcement-ready",
"full_workflow_required_when": [
{
"id": "risk-security",
"description": "Any change touching authentication, authorization, CSRF, encryption, logging redaction, file uploads, or API bootstrap/security behavior.",
"paths": [
"lib/Http/**",
"lib/Service/Access/**",
"lib/Support/Crypto.php",
"pages/api/**",
"pages/**"
]
},
{
"id": "risk-data-boundary",
"description": "Any change touching tenant-scoped data access, repository query boundaries, DB schema updates, or API contracts.",
"paths": [
"lib/Repository/**",
"db/updates/**",
"db/init/init.sql",
"docs/openapi.yaml"
]
},
{
"id": "risk-modules",
"description": "Any change touching module manifests, module runtime wiring, module routes, module providers, or module migrations/assets.",
"paths": [
"modules/*/module.php",
"lib/App/Module/**",
"storage/runtime/pages/**",
"web/modules/**"
]
},
{
"id": "risk-cross-layer",
"description": "Any feature/addition changing more than one architecture layer (Repository, Service, pages/templates/web, modules, config, db).",
"paths": [
"lib/**",
"pages/**",
"templates/**",
"web/**",
"modules/**",
"config/**",
"db/**"
]
}
],
"quick_fix_allowlist": [
"single-file typo fix without behavior change",
"single-file translation text/key correction without flow change",
"single-file CSS visual adjustment without behavioral JS or backend change",
"single-file docs-only update"
],
"gate_policy": {
"required_gates_always": [
"QG-001",
"QG-002",
"QG-003",
"QG-006",
"QG-008",
"QG-009"
],
"manual_non_blocking": [
"QG-005"
],
"periodic_non_blocking": [
"QG-007"
]
},
"ci_rollout": {
"target_platform": "gitea",
"blocking_enabled": false,
"phase_2_activation": "Enable required status checks in repository branch protection once qa-required is stable on runner infrastructure."
}
}

View File

@@ -23,10 +23,10 @@ Guard IDs live in `.agents/checks/guard-catalog.json` (guards where `reviewer` =
- `GR-UI-REUSE` existing JS/CSS checked before adding new functions/rules
## Quality Gates
- `QG-001` to `QG-003` are run unless explicitly out of scope
- required always (per `enforcement-policy.json`): `QG-001`, `QG-002`, `QG-003`, `QG-006`, `QG-008`, `QG-009`
- `QG-004` structural checks reported when relevant
- `QG-005` JS smoke for JS-touching changes
- `QG-006` PHP style check for PHP-touching changes
- `QG-007` composer-unused is periodic / non-blocking
# Security Review Checklist

View File

@@ -0,0 +1,173 @@
{
"version": "1.0.0",
"entries": [
{
"guard_id": "GR-CORE-003",
"enforcement_mode": "automated",
"evidence_source": [
"tests/Architecture/CoreStarterkitContractTest.php"
]
},
{
"guard_id": "GR-CORE-007",
"enforcement_mode": "hybrid",
"evidence_source": [
"tests/Architecture/ApiSchemaContractTest.php",
".agents/runs/<TASK>/review-code.json"
]
},
{
"guard_id": "GR-CORE-010",
"enforcement_mode": "automated",
"evidence_source": [
"tests/Architecture/DatabaseUpdatesContractTest.php"
]
},
{
"guard_id": "GR-CORE-011",
"enforcement_mode": "reviewer",
"evidence_source": [
".agents/runs/<TASK>/review-code.json"
]
},
{
"guard_id": "GR-CORE-012",
"enforcement_mode": "automated",
"evidence_source": [
"tests/Architecture/PostRedirectGetContractTest.php"
]
},
{
"guard_id": "GR-TEST-001",
"enforcement_mode": "reviewer",
"evidence_source": [
".agents/runs/<TASK>/review-code.json",
".agents/runs/<TASK>/review-acceptance.json"
]
},
{
"guard_id": "GR-TEST-002",
"enforcement_mode": "hybrid",
"evidence_source": [
"tests/Architecture/CoreStarterkitContractTest.php",
".agents/runs/<TASK>/review-code.json"
]
},
{
"guard_id": "GR-UI-014",
"enforcement_mode": "reviewer",
"evidence_source": [
".agents/runs/<TASK>/review-code.json",
".agents/runs/<TASK>/review-acceptance.json"
]
},
{
"guard_id": "GR-UI-LIST",
"enforcement_mode": "automated",
"evidence_source": [
"tests/Architecture/ListDataEndpointContractTest.php",
"tests/Architecture/ListTemplateContractTest.php"
]
},
{
"guard_id": "GR-UI-DETAIL",
"enforcement_mode": "automated",
"evidence_source": [
"tests/Architecture/DetailPageRuntimeContractTest.php",
"tests/Architecture/DetailActionPolicyRuntimeContractTest.php"
]
},
{
"guard_id": "GR-UI-A11Y",
"enforcement_mode": "automated",
"evidence_source": [
"tests/Architecture/AuthLoginTemplateAccessibilityContractTest.php",
"tests/Architecture/AuthLoginFieldAccessibilityContractTest.php"
]
},
{
"guard_id": "GR-UI-I18N",
"enforcement_mode": "automated",
"evidence_source": [
"tests/Architecture/I18nKeyCompletenessContractTest.php",
"tests/Architecture/ModuleI18nContractTest.php"
]
},
{
"guard_id": "GR-UI-REUSE",
"enforcement_mode": "hybrid",
"evidence_source": [
"tests/Architecture/CoreStarterkitContractTest.php",
".agents/runs/<TASK>/review-code.json"
]
},
{
"guard_id": "GR-SEC-001",
"enforcement_mode": "automated",
"evidence_source": [
"tests/Architecture/PostEndpointCsrfContractTest.php"
]
},
{
"guard_id": "GR-SEC-002",
"enforcement_mode": "automated",
"evidence_source": [
"tests/Architecture/SecurityLoggingRedactionContractTest.php",
"tests/Architecture/SecurityLoggingTelemetryContractTest.php"
]
},
{
"guard_id": "GR-SEC-003",
"enforcement_mode": "reviewer",
"evidence_source": [
".agents/runs/<TASK>/review-security.json"
]
},
{
"guard_id": "GR-SEC-004",
"enforcement_mode": "automated",
"evidence_source": [
"tests/Architecture/SecurityRemoteAssetContractTest.php"
]
},
{
"guard_id": "GR-SEC-005",
"enforcement_mode": "automated",
"evidence_source": [
"tests/Architecture/SecurityCryptoContractTest.php"
]
},
{
"guard_id": "GR-SEC-006",
"enforcement_mode": "hybrid",
"evidence_source": [
"tests/Architecture/FileStorageContractTest.php",
".agents/runs/<TASK>/review-security.json"
]
},
{
"guard_id": "GR-SEC-007",
"enforcement_mode": "automated",
"evidence_source": [
"tests/Architecture/ApiSessionIsolationContractTest.php"
]
},
{
"guard_id": "GR-SEC-008",
"enforcement_mode": "hybrid",
"evidence_source": [
"tests/Architecture/AuthzAdminUsersContractTest.php",
"tests/Architecture/AuthzApiBootstrapContractTest.php",
".agents/runs/<TASK>/review-security.json"
]
},
{
"guard_id": "GR-SEC-009",
"enforcement_mode": "hybrid",
"evidence_source": [
"tests/Architecture/ApiResourceContractTest.php",
".agents/runs/<TASK>/review-security.json"
]
}
]
}

View File

@@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "module-manifest.schema.json",
"$id": "https://corecore.local/schemas/module-manifest.schema.json",
"title": "Module Manifest Schema",
"description": "Declarative schema for module.php manifest files under modules/<id>/.",
"type": "object",
@@ -61,40 +61,53 @@
"default": []
},
"ui_slots": {
"type": "object",
"description": "Keyed by slot name (e.g. 'aside.tab_panel'). Values are arrays of contribution objects.",
"patternProperties": {
"^.+$": {
"type": "array",
"items": {
"type": "object",
"required": ["key"],
"properties": {
"key": { "type": "string", "minLength": 1 },
"label": { "type": "string" },
"icon": { "type": "string" },
"href": { "type": "string" },
"permission": { "type": "string" },
"panel_template": { "type": "string" },
"template": { "type": "string" },
"path": { "type": "string" },
"script": { "type": "string" },
"export": { "type": "string" },
"selector": { "type": "string" },
"scope": { "type": "string" },
"config_path": { "type": "string" },
"default_config": { "type": "object" },
"phase": { "type": "string", "enum": ["early", "default", "late"] },
"type": { "type": "string" },
"order": { "type": "integer", "default": 100 },
"details_storage": { "type": "string" },
"details_open_active": { "type": "boolean" },
"base_url": { "type": "string" },
"group": { "type": "string", "description": "Sidebar nav group key for grouping related items under a details/summary section." }
"anyOf": [
{
"type": "object",
"patternProperties": {
"^.+$": {
"type": "array",
"items": {
"type": "object",
"required": ["key"],
"properties": {
"key": { "type": "string", "minLength": 1 },
"label": { "type": "string" },
"icon": { "type": "string" },
"href": { "type": "string" },
"permission": { "type": "string" },
"panel_template": { "type": "string" },
"template": { "type": "string" },
"path": { "type": "string" },
"script": { "type": "string" },
"export": { "type": "string" },
"selector": { "type": "string" },
"scope": { "type": "string" },
"config_path": { "type": "string" },
"default_config": {
"anyOf": [
{ "type": "object" },
{ "type": "array", "maxItems": 0 }
]
},
"phase": { "type": "string", "enum": ["early", "default", "late"] },
"type": { "type": "string" },
"order": { "type": "integer", "default": 100 },
"details_storage": { "type": "string" },
"details_open_active": { "type": "boolean" },
"base_url": { "type": "string" },
"group": { "type": "string", "description": "Sidebar nav group key for grouping related items under a details/summary section." }
}
}
}
}
},
{
"type": "array",
"maxItems": 0
}
},
],
"default": {}
},
"search_resources": {
@@ -103,14 +116,22 @@
"default": []
},
"asset_groups": {
"type": "object",
"description": "Asset group name → file list.",
"patternProperties": {
"^.+$": {
"anyOf": [
{
"type": "object",
"patternProperties": {
"^.+$": {
"type": "array",
"items": { "type": "string" }
}
}
},
{
"type": "array",
"items": { "type": "string" }
"maxItems": 0
}
},
],
"default": {}
},
"layout_context_providers": {
@@ -136,8 +157,8 @@
"properties": {
"key": { "type": "string", "minLength": 1 },
"description": { "type": "string", "minLength": 1 },
"active": { "type": "boolean", "default": true },
"is_system": { "type": "boolean", "default": true }
"active": { "type": ["boolean", "integer"], "default": true },
"is_system": { "type": ["boolean", "integer"], "default": true }
},
"additionalProperties": false
},
@@ -177,22 +198,30 @@
"default": []
},
"event_listeners": {
"type": "object",
"description": "Event name → list of listener descriptors.",
"patternProperties": {
"^.+$": {
"type": "array",
"items": {
"type": "object",
"required": ["class", "method"],
"properties": {
"class": { "type": "string", "minLength": 1, "description": "FQCN implementing EventListener." },
"method": { "type": "string", "minLength": 1 }
},
"additionalProperties": false
"anyOf": [
{
"type": "object",
"patternProperties": {
"^.+$": {
"type": "array",
"items": {
"type": "object",
"required": ["class", "method"],
"properties": {
"class": { "type": "string", "minLength": 1, "description": "FQCN implementing EventListener." },
"method": { "type": "string", "minLength": 1 }
},
"additionalProperties": false
}
}
}
},
{
"type": "array",
"maxItems": 0
}
},
],
"default": {}
},
"deactivation_handler": {

View File

@@ -5,6 +5,12 @@
1. `docker compose exec php vendor/bin/phpunit`
2. `docker compose exec php vendor/bin/phpstan analyse -c phpstan.neon --no-progress`
3. `docker compose exec php vendor/bin/phpunit tests/Architecture/CoreStarterkitContractTest.php`
4. `docker compose exec php vendor/bin/php-cs-fixer fix --config=tools/php-cs-fixer/.php-cs-fixer.dist.php --dry-run --diff --verbose`
5. `bin/docs-link-check.sh`
6. `bin/codex-skills-sync.sh --check`
Policy-Hinweis:
- Verbindliche Enforcement-Einteilung (`required`, `manual_non_blocking`, `periodic_non_blocking`) wird zentral in `/.agents/checks/enforcement-policy.json` gepflegt.
## Struktur-Gates (schnell)

View File

@@ -22,6 +22,8 @@ Primary goals:
Source of truth:
- Guard catalog (22 guards): `.agents/checks/guard-catalog.json`
- Quality gates (9 gates): `.agents/checks/quality-gates.json`
- Enforcement policy (workflow trigger + gate enforcement): `.agents/checks/enforcement-policy.json`
- Guard enforcement map (guard -> automated/hybrid/reviewer evidence): `.agents/checks/guard-enforcement-map.json`
- Contracts: `.agents/contracts/`
---
@@ -81,6 +83,17 @@ analyzed → planned → executing → reviewing → finalize → done
The reviewing state runs Code Reviewer, Security Reviewer, and Acceptance Tester.
If any reviewer returns `FAIL`, state goes back to `executing` with explicit findings.
## Workflow Trigger Policy
Workflow triggering is risk-based and centrally defined in:
- `.agents/checks/enforcement-policy.json` (`full_workflow_required_when`)
- `.agents/checks/enforcement-policy.json` (`quick_fix_allowlist`)
Interpretation:
- Full workflow is mandatory for risk/security/data-boundary/module/cross-layer changes
- Quick fixes are only exempt if they match the explicit allowlist
- `>1 layer` remains a useful heuristic but is no longer the sole trigger
## Handover Artifacts
| Role | Artifact |
@@ -123,3 +136,5 @@ The following concerns are covered by QG-001/QG-003/QG-004 and do NOT need manua
- Repository sanitizeLimitOffset (RepositoryInterfaceContractTest)
- List init standard, legacy filter toggle, template RBAC (architecture tests)
- Component lifecycle contract (architecture tests)
- Guard reference integrity (`GR-*`/`QG-*`) across docs/agents/tests/bin
- Guard enforcement mapping completeness and automated evidence file existence