From bd0fc1e4b0dec4d2a71dd7d236c4b09062a0cb05 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Thu, 19 Mar 2026 12:36:48 +0100 Subject: [PATCH 01/18] 6869: Add agents.md and Claude Code configuration Add vendor-neutral agents.md with project context for AI coding agents, and Claude Code settings with permissions, hooks, and plugins. Update README with AI coding agents section describing the setup. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/settings.json | 107 +++++++++++++++++++++++++++++++ README.md | 32 ++++++++++ agents.md | 142 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 281 insertions(+) create mode 100644 .claude/settings.json create mode 100644 agents.md diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..f000cbb --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,107 @@ +{ + "$schema": "https://json.schemastore.org/claude-code-settings.json", + "env": { + "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" + }, + "permissions": { + "allow": [ + "Bash(cat:*)", + "Bash(diff:*)", + "Bash(echo:*)", + "Bash(find:*)", + "Bash(gh:*)", + "Bash(git:*)", + "Bash(grep:*)", + "Bash(head:*)", + "Bash(ls:*)", + "Bash(pwd)", + "Bash(tail:*)", + "Bash(tree:*)", + "Bash(wc:*)", + "Bash(which:*)", + "Bash(docker compose:*)", + "Bash(docker network:*)" + ], + "deny": [ + "Bash(rm -rf:*)", + "Read(./.env.local)", + "Read(./.env.local.*)", + "Read(./config/secrets/*)" + ], + "ask": [ + "Bash(gh issue create:*)", + "Bash(gh issue close:*)", + "Bash(gh issue delete:*)", + "Bash(gh issue edit:*)", + "Bash(gh issue comment:*)", + "Bash(gh pr create:*)", + "Bash(gh pr close:*)", + "Bash(gh pr merge:*)", + "Bash(gh pr edit:*)", + "Bash(gh pr comment:*)", + "Bash(gh pr review:*)", + "Bash(gh release create:*)", + "Bash(gh release delete:*)", + "Bash(gh release edit:*)", + "Bash(gh repo create:*)", + "Bash(gh repo delete:*)", + "Bash(gh label create:*)", + "Bash(gh label delete:*)", + "Bash(gh label edit:*)", + "Bash(git push:*)", + "Bash(git branch -d:*)", + "Bash(git branch -D:*)", + "Bash(git tag -d:*)", + "Bash(git tag -a:*)", + "Bash(git tag :*)", + "Bash(git reset:*)", + "Bash(git rebase:*)", + "Bash(git merge:*)", + "Bash(git stash drop:*)", + "Bash(git clean:*)", + "Bash(git checkout -- :*)", + "Bash(git restore:*)", + "Bash(git commit:*)" + ] + }, + "hooks": { + "PostToolUse": [ + { + "matcher": "Write|Edit", + "hooks": [ + { + "type": "command", + "command": "case \"$CLAUDE_FILE_PATH\" in *.php) docker compose exec -T phpfpm vendor/bin/php-cs-fixer fix --quiet \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac", + "timeout": 30 + }, + { + "type": "command", + "command": "case \"$CLAUDE_FILE_PATH\" in *.yaml|*.yml) docker compose exec -T phpfpm bin/console lint:yaml \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac", + "timeout": 15 + }, + { + "type": "command", + "command": "case \"$CLAUDE_FILE_PATH\" in *.twig) docker compose exec -T phpfpm bin/console lint:twig \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac", + "timeout": 15 + }, + { + "type": "command", + "command": "case \"$CLAUDE_FILE_PATH\" in *.json) python3 -m json.tool \"$CLAUDE_FILE_PATH\" > /dev/null 2>&1 || true ;; esac", + "timeout": 10 + } + ] + } + ] + }, + "enabledPlugins": { + "php-lsp@claude-plugins-official": true, + "code-simplifier@claude-plugins-official": true, + "context7@claude-plugins-official": true, + "code-review@claude-plugins-official": true, + "security-guidance@claude-plugins-official": true, + "playwright@claude-plugins-official": true, + "feature-dev@claude-plugins-official": true + }, + "alwaysThinkingEnabled": true, + "defaultMode": "acceptEdits" +} diff --git a/README.md b/README.md index a1fc813..11cf35e 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ [![Codecov](https://img.shields.io/codecov/c/github/itk-dev/devops_itksites?style=flat-square&logo=codecov)](https://codecov.io/gh/itk-dev/devops_itksites) [![GitHub last commit](https://img.shields.io/github/last-commit/itk-dev/devops_itksites?style=flat-square)](https://github.com/itk-dev/devops_itksites/commits/develop/) [![GitHub License](https://img.shields.io/github/license/itk-dev/devops_itksites?style=flat-square)](https://github.com/itk-dev/devops_itksites/blob/develop/LICENSE) +[![agents.md](https://img.shields.io/badge/%F0%9F%A4%96_agents.md-AI%20ready-8A2BE2?style=flat-square)](https://github.com/itk-dev/devops_itksites/blob/develop/agents.md) This is our internal server and site registration tool. It works in tandem with our @@ -125,3 +126,34 @@ during development to automatically rebuild assets when source files change. ```sh docker compose run --rm node yarn coding-standards-check ``` + +### 🤖 AI coding agents + +This project includes an [`agents.md`](agents.md) file that provides project +context for AI coding agents. The file describes the project architecture, +technology stack, development commands, CI/CD setup, and coding conventions. + +`agents.md` is a vendor-neutral standard supported by tools such as +[Claude Code](https://claude.ai/claude-code), +[OpenCode](https://opencode.ai/), and others. + +Tool-specific configuration (permissions, hooks, plugins) lives in `.claude/` +and is not portable across tools. + +#### Claude Code plugins + +The following plugins are enabled in `.claude/settings.json`: + +| Plugin | Purpose | Source | +|---|---|---| +| `php-lsp` | PHP language server for type-aware code intelligence | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| `context7` | Up-to-date documentation lookup for Symfony, Doctrine, API Platform, etc. | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| `code-review` | Pull request code review | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| `code-simplifier` | Suggests clarity and maintainability improvements | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| `security-guidance` | Flags potential security issues (OWASP, injection, etc.) | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| `playwright` | Browser automation for debugging and testing the EasyAdmin UI | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| `feature-dev` | Guided feature development with codebase exploration and architecture focus | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | + +> **Note:** The `php-lsp` plugin requires [Intelephense](https://intelephense.com/) +> installed globally: `npm install -g intelephense`. All other plugins work +> without additional dependencies. diff --git a/agents.md b/agents.md new file mode 100644 index 0000000..6624c1a --- /dev/null +++ b/agents.md @@ -0,0 +1,142 @@ +# 🤖 Code Agents - DevOps ITKsites + +## Project Overview + +**DevOps ITKsites** is an internal Symfony application for server and site +registration/monitoring at ITK Dev. It receives `DetectionResults` from the +[ITK sites server harvester](https://github.com/itk-dev/devops_itkServerHarvest) +and processes them asynchronously to track servers, sites, domains, Docker +images, packages, modules, CVEs, and git repositories. + +## Technology Stack + +- **Language**: PHP 8.4+ (Symfony 7.3) +- **API**: API Platform 4.0 (REST) +- **Admin UI**: EasyAdmin 4.x +- **Database**: Doctrine ORM 3.x / DBAL 4.x with MariaDB +- **Messaging**: Symfony Messenger (AMQP/RabbitMQ) +- **Auth**: OpenID Connect (`itk-dev/openid-connect-bundle`) +- **Frontend**: Webpack Encore, Stimulus.js +- **Testing**: PHPUnit 11+ +- **Code Quality**: PHP-CS-Fixer, PHPStan, Rector + +## Architecture + +```mermaid +graph TD + A[Harvester] -->|POST DetectionResult| B[API Platform REST endpoint] + B --> C[Symfony Messenger] + C --> D[Async Message Handlers] + D --> D1[DirectoryHandler] + D --> D2[DockerImageHandler] + D --> D3[DrupalHandler] + D --> D4[GitHandler] + D --> D5[NginxHandler] + D --> D6[SymfonyHandler] + D1 & D2 & D3 & D4 & D5 & D6 --> E[Doctrine ORM] + E --> F[MariaDB] + F --> G[EasyAdmin UI] +``` + +### Key Directories + +| Directory | Purpose | +|---|---| +| `src/Entity/` | ~20 Doctrine entities (Server, Site, Domain, Installation, Package, DockerImage, Advisory, etc.) | +| `src/Handler/` | DetectionResult handlers (Directory, Docker, Drupal, Git, Nginx, Symfony) | +| `src/MessageHandler/` | Async message processing (PersistDetectionResult, ProcessDetectionResult) | +| `src/Admin/` | EasyAdmin CRUD controllers | +| `src/ApiResource/` | API Platform resource definitions | +| `src/Service/` | Factories (PackageVersion, ModuleVersion, Advisory) and export services | +| `src/Repository/` | Doctrine repositories | +| `config/packages/` | Bundle configurations | +| `migrations/` | Doctrine migrations | +| `fixtures/` | Hautelook/Alice test fixtures | +| `tests/` | PHPUnit tests (Api, Controller, MessageHandler) | + +### Data Flow + +All analyzed data (sites, installations, domains, packages, etc.) can be +truncated and rebuilt by replaying DetectionResults. Manually maintained data +(Servers, OIDC setups, Service Certificates) is separate and must be preserved. + +## Development Environment + +```sh +# Start services (MariaDB, PHP-FPM 8.4, Nginx, Mailpit) +docker compose pull && docker compose up --detach + +# Install dependencies +docker compose exec phpfpm composer install + +# Run migrations +docker compose exec phpfpm bin/console doctrine:migrations:migrate --no-interaction + +# Load fixtures +docker compose exec phpfpm composer fixtures + +# Login as admin (after fixtures) +docker compose exec phpfpm bin/console itk-dev:openid-connect:login admin@example.com + +# Process message queues +docker compose exec phpfpm composer queues + +# Build frontend assets +docker compose run --rm node yarn install && docker compose run --rm node yarn build +``` + +## Quality Checks + +All commands run inside Docker containers: + +```sh +# PHP coding standards (PHP-CS-Fixer) +docker compose exec phpfpm composer coding-standards-check +docker compose exec phpfpm composer coding-standards-apply + +# PHPUnit tests (creates test DB, runs migrations, executes tests) +docker compose exec phpfpm composer tests + +# Frontend coding standards +docker compose run --rm node yarn coding-standards-check + +# API spec export (must be committed) +docker compose exec phpfpm composer update-api-spec +``` + +## CI/CD + +### GitHub Actions (`pr.yaml`) + +Pull requests run these checks: + +1. **Composer validation** - validates and installs (prod + dev) +2. **Doctrine schema validation** - migrations + schema check against MariaDB +3. **PHP-CS-Fixer** - coding standards +4. **PHPUnit** - unit/integration tests with MariaDB +5. **API spec validation** - ensures exported OpenAPI spec is up to date +6. **Fixtures** - verifies fixtures load successfully +7. **Asset build** - verifies frontend assets compile +8. **Changelog** - ensures CHANGELOG.md is updated + +### Woodpecker CI (deployment) + +- `stg.yml` - Deploys to staging on push to develop +- `prod.yml` - Deploys to production on release (Ansible playbook, runs migrations + transport setup) + +## PR Guidelines + +- PRs must link to a ticket +- Code must pass all CI checks (tests, coding standards, static analysis) +- CHANGELOG.md must be updated +- UI changes require screenshots +- Base branch: `develop` + +## Important Conventions + +- Entity classes extend `AbstractBaseEntity` (provides `id`, `createdAt`, `updatedAt`) +- Detection handlers implement `DetectionResultHandlerInterface` +- Handlers are auto-tagged and injected via tagged iterator in `services.yaml` +- Async processing uses Symfony Messenger with AMQP transport +- Environment-specific config goes in `.env.local` (not committed) +- API specs (`public/api-spec-v1.yaml` and `.json`) must be regenerated and committed when API changes \ No newline at end of file From 1e7c04c249c7beb360338a1d6377be074848c87a Mon Sep 17 00:00:00 2001 From: turegjorup Date: Thu, 19 Mar 2026 12:44:49 +0100 Subject: [PATCH 02/18] &869: Update Chnagelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf0a0af..6d2fdf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#58](https://github.com/itk-dev/devops_itksites/pull/58) 5002: Added export to everything +- [#62](https://github.com/itk-dev/devops_itksites/pull/62) + 6869: Add agents.md and Claude Code configuration for AI coding agents ## [1.8.10] - 2025-07-02 From 30a9a5340521b6c439a6a91af71b79c25fd5e635 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Thu, 19 Mar 2026 12:44:49 +0100 Subject: [PATCH 03/18] 6869: Update Changelog Co-Authored-By: Claude Opus 4.6 (1M context) --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf0a0af..6d2fdf3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#58](https://github.com/itk-dev/devops_itksites/pull/58) 5002: Added export to everything +- [#62](https://github.com/itk-dev/devops_itksites/pull/62) + 6869: Add agents.md and Claude Code configuration for AI coding agents ## [1.8.10] - 2025-07-02 From 3d5ac2dc9939d1a30121239185e92bc9cfa0e633 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Wed, 25 Mar 2026 13:54:27 +0100 Subject: [PATCH 04/18] 6869: Rename agents.md to claude.md and update settings Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/settings.json | 1 + agents.md => claude.md | 0 2 files changed, 1 insertion(+) rename agents.md => claude.md (100%) diff --git a/.claude/settings.json b/.claude/settings.json index f000cbb..263375d 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -16,6 +16,7 @@ "Bash(ls:*)", "Bash(pwd)", "Bash(tail:*)", + "Bash(task:*)", "Bash(tree:*)", "Bash(wc:*)", "Bash(which:*)", diff --git a/agents.md b/claude.md similarity index 100% rename from agents.md rename to claude.md From f07447d608b3c222298c213aef1251dd1def3bce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ture=20Gj=C3=B8rup?= Date: Wed, 25 Mar 2026 14:07:12 +0100 Subject: [PATCH 05/18] Update .claude/settings.json Co-authored-by: Jesper Pedersen --- .claude/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.claude/settings.json b/.claude/settings.json index f000cbb..f33ed30 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -100,7 +100,8 @@ "code-review@claude-plugins-official": true, "security-guidance@claude-plugins-official": true, "playwright@claude-plugins-official": true, - "feature-dev@claude-plugins-official": true + "feature-dev@claude-plugins-official": true, + "itkdev-skills@itkdev-marketplace": true }, "alwaysThinkingEnabled": true, "defaultMode": "acceptEdits" From 8c33fafd09eab56bc899c21991d284ba702688ba Mon Sep 17 00:00:00 2001 From: turegjorup Date: Wed, 25 Mar 2026 14:18:59 +0100 Subject: [PATCH 06/18] 6869: Add PHPStan job to PR workflow Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/pr.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 5ddf9eb..5625c95 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -21,6 +21,21 @@ jobs: docker compose exec phpfpm bin/console messenger:setup-transports failed docker compose exec phpfpm bin/console doctrine:schema:validate + phpstan: + runs-on: ubuntu-latest + name: PHPStan + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Create docker network + run: docker network create frontend + + - name: Run PHPStan + run: | + docker compose run --rm phpfpm composer install --no-interaction + docker compose run --rm phpfpm vendor/bin/phpstan analyse + phpunit: runs-on: ubuntu-latest name: PHP Unit tests From 4b47640397d34a5731c5c894b5cdbbb952e8266f Mon Sep 17 00:00:00 2001 From: turegjorup Date: Wed, 25 Mar 2026 14:19:18 +0100 Subject: [PATCH 07/18] 6869: Improve Claude Code hooks and permissions - Add PHPStan, twig-cs-fixer, and composer normalize PostToolUse hooks - Add SessionStart hook to ensure Docker services are running - Add Stop hook for Symfony DI container validation - Scope docker compose permissions (destructive commands require confirmation) - Restore php-lsp plugin - Set COMPOSE_USER env var Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/settings.json | 59 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/.claude/settings.json b/.claude/settings.json index 263375d..5582e45 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-settings.json", "env": { - "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" + "COMPOSE_USER": "deploy" }, "permissions": { "allow": [ @@ -20,19 +20,34 @@ "Bash(tree:*)", "Bash(wc:*)", "Bash(which:*)", - "Bash(docker compose:*)", + "Bash(docker compose exec:*)", + "Bash(docker compose run:*)", + "Bash(docker compose up:*)", + "Bash(docker compose ps:*)", + "Bash(docker compose logs:*)", + "Bash(docker compose top:*)", + "Bash(docker compose config:*)", + "Bash(docker compose pull:*)", + "Bash(docker compose images:*)", "Bash(docker network:*)" ], "deny": [ "Bash(rm -rf:*)", + "Bash(gh issue delete:*)", + "Bash(gh release delete:*)", + "Bash(gh repo delete:*)", + "Bash(gh label delete:*)", "Read(./.env.local)", "Read(./.env.local.*)", "Read(./config/secrets/*)" ], "ask": [ + "Bash(docker compose down:*)", + "Bash(docker compose stop:*)", + "Bash(docker compose rm:*)", + "Bash(docker compose restart:*)", "Bash(gh issue create:*)", "Bash(gh issue close:*)", - "Bash(gh issue delete:*)", "Bash(gh issue edit:*)", "Bash(gh issue comment:*)", "Bash(gh pr create:*)", @@ -42,12 +57,9 @@ "Bash(gh pr comment:*)", "Bash(gh pr review:*)", "Bash(gh release create:*)", - "Bash(gh release delete:*)", "Bash(gh release edit:*)", "Bash(gh repo create:*)", - "Bash(gh repo delete:*)", "Bash(gh label create:*)", - "Bash(gh label delete:*)", "Bash(gh label edit:*)", "Bash(git push:*)", "Bash(git branch -d:*)", @@ -66,6 +78,19 @@ ] }, "hooks": { + "SessionStart": [ + { + "matcher": "startup", + "hooks": [ + { + "type": "command", + "command": "docker compose up --detach --quiet-pull 2>/dev/null || true", + "timeout": 60, + "statusMessage": "Starting Docker services..." + } + ] + } + ], "PostToolUse": [ { "matcher": "Write|Edit", @@ -77,18 +102,30 @@ }, { "type": "command", - "command": "case \"$CLAUDE_FILE_PATH\" in *.yaml|*.yml) docker compose exec -T phpfpm bin/console lint:yaml \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac", - "timeout": 15 + "command": "case \"$CLAUDE_FILE_PATH\" in *.php) docker compose exec -T phpfpm vendor/bin/phpstan analyse --no-progress --error-format=raw \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac", + "timeout": 30 }, { "type": "command", - "command": "case \"$CLAUDE_FILE_PATH\" in *.twig) docker compose exec -T phpfpm bin/console lint:twig \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac", + "command": "case \"$CLAUDE_FILE_PATH\" in *.twig) docker compose exec -T phpfpm vendor/bin/twig-cs-fixer lint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac", "timeout": 15 }, { "type": "command", - "command": "case \"$CLAUDE_FILE_PATH\" in *.json) python3 -m json.tool \"$CLAUDE_FILE_PATH\" > /dev/null 2>&1 || true ;; esac", - "timeout": 10 + "command": "case \"$CLAUDE_FILE_PATH\" in */composer.json) docker compose exec -T phpfpm composer normalize --quiet 2>/dev/null || true ;; esac", + "timeout": 30 + } + ] + } + ], + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "docker compose exec -T phpfpm bin/console lint:container 2>/dev/null || true", + "timeout": 30, + "statusMessage": "Validating Symfony DI container..." } ] } From 560e5e5666e3776ab8dba90aa85d4450456db624 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Wed, 25 Mar 2026 14:19:27 +0100 Subject: [PATCH 08/18] 6869: Clarify local-only dev credentials in docker-compose.override Replace opaque RabbitMQ Erlang cookie with self-documenting value and add comment indicating these are local dev credentials. Co-Authored-By: Claude Opus 4.6 (1M context) --- docker-compose.override.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 77c259d..73f8b43 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -9,7 +9,7 @@ services: environment: - RABBITMQ_DEFAULT_USER=user - RABBITMQ_DEFAULT_PASS=password - - RABBITMQ_ERLANG_COOKIE='d53f219cd9376f8f440aaf9889f315ab' + - RABBITMQ_ERLANG_COOKIE='local-dev-cookie-not-a-secret' healthcheck: test: rabbitmq-diagnostics check_port_connectivity interval: 1s From 2ad001c7eced756385df17838f56d42597c74475 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Wed, 25 Mar 2026 14:25:28 +0100 Subject: [PATCH 09/18] 6869: Update claude.md for Symfony 8.0 and PHP 8.5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PHP 8.4+ → 8.5+, Symfony 7.3 → 8.0 - EasyAdmin 4.x → 5.x, PHPUnit 11+ → 13+ - Expand CI section to reflect all 14 workflow checks Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 18 ++++++++--------- claude.md | 58 ++++++++++++++++++++++++++++++------------------------- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index bcbb48b..2928aa9 100644 --- a/README.md +++ b/README.md @@ -149,15 +149,15 @@ and is not portable across tools. The following plugins are enabled in `.claude/settings.json`: -| Plugin | Purpose | Source | -|---|---|---| -| `php-lsp` | PHP language server for type-aware code intelligence | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | -| `context7` | Up-to-date documentation lookup for Symfony, Doctrine, API Platform, etc. | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | -| `code-review` | Pull request code review | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | -| `code-simplifier` | Suggests clarity and maintainability improvements | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | -| `security-guidance` | Flags potential security issues (OWASP, injection, etc.) | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | -| `playwright` | Browser automation for debugging and testing the EasyAdmin UI | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | -| `feature-dev` | Guided feature development with codebase exploration and architecture focus | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| Plugin | Purpose | Source | +|---------------------|-----------------------------------------------------------------------------|------------------------------------------------------------------------------| +| `php-lsp` | PHP language server for type-aware code intelligence | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| `context7` | Up-to-date documentation lookup for Symfony, Doctrine, API Platform, etc. | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| `code-review` | Pull request code review | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| `code-simplifier` | Suggests clarity and maintainability improvements | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| `security-guidance` | Flags potential security issues (OWASP, injection, etc.) | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| `playwright` | Browser automation for debugging and testing the EasyAdmin UI | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | +| `feature-dev` | Guided feature development with codebase exploration and architecture focus | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | > **Note:** The `php-lsp` plugin requires [Intelephense](https://intelephense.com/) > installed globally: `npm install -g intelephense`. All other plugins work diff --git a/claude.md b/claude.md index 6624c1a..a83a1af 100644 --- a/claude.md +++ b/claude.md @@ -10,14 +10,14 @@ images, packages, modules, CVEs, and git repositories. ## Technology Stack -- **Language**: PHP 8.4+ (Symfony 7.3) +- **Language**: PHP 8.5+ (Symfony 8.0) - **API**: API Platform 4.0 (REST) -- **Admin UI**: EasyAdmin 4.x +- **Admin UI**: EasyAdmin 5.x - **Database**: Doctrine ORM 3.x / DBAL 4.x with MariaDB - **Messaging**: Symfony Messenger (AMQP/RabbitMQ) - **Auth**: OpenID Connect (`itk-dev/openid-connect-bundle`) - **Frontend**: Webpack Encore, Stimulus.js -- **Testing**: PHPUnit 11+ +- **Testing**: PHPUnit 13+ - **Code Quality**: PHP-CS-Fixer, PHPStan, Rector ## Architecture @@ -40,19 +40,19 @@ graph TD ### Key Directories -| Directory | Purpose | -|---|---| -| `src/Entity/` | ~20 Doctrine entities (Server, Site, Domain, Installation, Package, DockerImage, Advisory, etc.) | -| `src/Handler/` | DetectionResult handlers (Directory, Docker, Drupal, Git, Nginx, Symfony) | -| `src/MessageHandler/` | Async message processing (PersistDetectionResult, ProcessDetectionResult) | -| `src/Admin/` | EasyAdmin CRUD controllers | -| `src/ApiResource/` | API Platform resource definitions | -| `src/Service/` | Factories (PackageVersion, ModuleVersion, Advisory) and export services | -| `src/Repository/` | Doctrine repositories | -| `config/packages/` | Bundle configurations | -| `migrations/` | Doctrine migrations | -| `fixtures/` | Hautelook/Alice test fixtures | -| `tests/` | PHPUnit tests (Api, Controller, MessageHandler) | +| Directory | Purpose | +|-----------------------|--------------------------------------------------------------------------------------------------| +| `src/Entity/` | ~20 Doctrine entities (Server, Site, Domain, Installation, Package, DockerImage, Advisory, etc.) | +| `src/Handler/` | DetectionResult handlers (Directory, Docker, Drupal, Git, Nginx, Symfony) | +| `src/MessageHandler/` | Async message processing (PersistDetectionResult, ProcessDetectionResult) | +| `src/Admin/` | EasyAdmin CRUD controllers | +| `src/ApiResource/` | API Platform resource definitions | +| `src/Service/` | Factories (PackageVersion, ModuleVersion, Advisory) and export services | +| `src/Repository/` | Doctrine repositories | +| `config/packages/` | Bundle configurations | +| `migrations/` | Doctrine migrations | +| `fixtures/` | Hautelook/Alice test fixtures | +| `tests/` | PHPUnit tests (Api, Controller, MessageHandler) | ### Data Flow @@ -63,7 +63,7 @@ truncated and rebuilt by replaying DetectionResults. Manually maintained data ## Development Environment ```sh -# Start services (MariaDB, PHP-FPM 8.4, Nginx, Mailpit) +# Start services (MariaDB, PHP-FPM 8.5, Nginx, Mailpit) docker compose pull && docker compose up --detach # Install dependencies @@ -110,14 +110,20 @@ docker compose exec phpfpm composer update-api-spec Pull requests run these checks: -1. **Composer validation** - validates and installs (prod + dev) -2. **Doctrine schema validation** - migrations + schema check against MariaDB -3. **PHP-CS-Fixer** - coding standards -4. **PHPUnit** - unit/integration tests with MariaDB -5. **API spec validation** - ensures exported OpenAPI spec is up to date -6. **Fixtures** - verifies fixtures load successfully -7. **Asset build** - verifies frontend assets compile -8. **Changelog** - ensures CHANGELOG.md is updated +1. **Composer** (`composer.yaml`) - validates, normalizes, and audits +2. **Doctrine schema validation** (`pr.yaml`) - migrations + schema check against MariaDB +3. **PHP-CS-Fixer** (`php.yaml`) - PHP coding standards +4. **PHPStan** (`pr.yaml`) - static analysis (level 6) +5. **PHPUnit** (`pr.yaml`) - unit/integration tests with MariaDB + coverage +6. **Twig** (`twig.yaml`) - Twig coding standards (twig-cs-fixer) +7. **YAML** (`yaml.yaml`) - YAML formatting (Prettier) +8. **Markdown** (`markdown.yaml`) - Markdown linting (markdownlint) +9. **JavaScript** (`javascript.yaml`) - JS formatting (Prettier) +10. **Styles** (`styles.yaml`) - CSS/SCSS formatting (Prettier) +11. **API spec** (`api-spec.yaml`) - ensures exported OpenAPI spec is up to date +12. **Fixtures** (`pr.yaml`) - verifies fixtures load successfully +13. **Asset build** (`pr.yaml`) - verifies frontend assets compile +14. **Changelog** (`changelog.yaml`) - ensures CHANGELOG.md is updated ### Woodpecker CI (deployment) @@ -139,4 +145,4 @@ Pull requests run these checks: - Handlers are auto-tagged and injected via tagged iterator in `services.yaml` - Async processing uses Symfony Messenger with AMQP transport - Environment-specific config goes in `.env.local` (not committed) -- API specs (`public/api-spec-v1.yaml` and `.json`) must be regenerated and committed when API changes \ No newline at end of file +- API specs (`public/api-spec-v1.yaml` and `.json`) must be regenerated and committed when API changes From 9a88a0033b08cdbe91284c5e785207ee52a70a4a Mon Sep 17 00:00:00 2001 From: turegjorup Date: Wed, 25 Mar 2026 14:26:15 +0100 Subject: [PATCH 10/18] =?UTF-8?q?6869:=20Fix=20typo=20in=20config=20refere?= =?UTF-8?q?nce=20(@var=20=E2=86=92=20@type)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- config/reference.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/reference.php b/config/reference.php index 7c1b9ad..85a036d 100644 --- a/config/reference.php +++ b/config/reference.php @@ -1360,7 +1360,7 @@ * mercure?: bool|array{ * enabled?: bool|Param, // Default: false * hub_url?: scalar|Param|null, // The URL sent in the Link HTTP header. If not set, will default to the URL for MercureBundle's default hub. // Default: null - * include_type?: bool|Param, // Always include @var in updates (including delete ones). // Default: false + * include_type?: bool|Param, // Always include @type in updates (including delete ones). // Default: false * }, * messenger?: bool|array{ * enabled?: bool|Param, // Default: true From 9344dcaac8fdeabdcac31f5c52c3cd6a5776992a Mon Sep 17 00:00:00 2001 From: turegjorup Date: Fri, 27 Mar 2026 10:53:54 +0100 Subject: [PATCH 11/18] 6869: Fix FieldCollection::new() removed in EasyAdmin 5.x Use plain constructor instead of the removed static factory method, fixing PHPStan staticMethod.notFound errors. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/Trait/ExportCrudControllerTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Trait/ExportCrudControllerTrait.php b/src/Trait/ExportCrudControllerTrait.php index 8880d58..d02b687 100644 --- a/src/Trait/ExportCrudControllerTrait.php +++ b/src/Trait/ExportCrudControllerTrait.php @@ -47,7 +47,7 @@ public function export(AdminContext $context): Response assert($this instanceof AbstractCrudController); // Lifted from self::index(). - $fields = FieldCollection::new($this->configureFields(Crud::PAGE_INDEX)); + $fields = new FieldCollection($this->configureFields(Crud::PAGE_INDEX)); $context->getCrud()->setFieldAssets($this->getFieldAssets($fields)); $filters = $this->filterFactory->create($context->getCrud()->getFiltersConfig(), $fields, $context->getEntity()); From 39144a69254aa5f514ad745971fad621ab69b029 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Fri, 27 Mar 2026 11:05:53 +0100 Subject: [PATCH 12/18] 6869: Update task file with "pr.actions" check --- Taskfile.yml | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/Taskfile.yml b/Taskfile.yml index 9c4494a..108d803 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -174,6 +174,76 @@ tasks: COMPOSE_ARGS: run --rm prettier '**/*.{yml,yaml}' --check --no-error-on-unmatched-pattern silent: true + # Composer checks (mirrors composer.yaml CI) + + composer:check: + desc: Validate, normalize, and audit composer + cmds: + - task: compose + vars: + COMPOSE_ARGS: exec phpfpm composer validate --strict + - task: compose + vars: + COMPOSE_ARGS: exec phpfpm composer normalize --dry-run + - task: compose + vars: + COMPOSE_ARGS: exec phpfpm composer audit + + # Analysis + + analysis:php: + aliases: [analyze:php] + desc: Run PHPStan static analysis + cmds: + - task: compose + vars: + COMPOSE_ARGS: exec phpfpm vendor/bin/phpstan + silent: true + + # Test matrix (mirrors pr.yaml CI jobs) + + test:matrix: + desc: Run full test matrix (tests, schema validation, fixtures, assets) + cmds: + - task: tests + - task: test:doctrine-schema + - task: test:fixtures + - task: test:build-assets + + test:doctrine-schema: + desc: Validate Doctrine schema against database + cmds: + - task: console + vars: + CONSOLE_ARGS: doctrine:schema:validate + + test:fixtures: + desc: Verify fixtures load successfully + cmds: + - task: console + vars: + CONSOLE_ARGS: hautelook:fixtures:load --no-interaction + + test:build-assets: + desc: Verify frontend assets compile + cmds: + - task: compose + vars: + COMPOSE_ARGS: run --rm node yarn install + - task: compose + vars: + COMPOSE_ARGS: run --rm node yarn build + + # CI + + pr:actions: + desc: Run all CI checks locally + cmds: + - task: composer:check + - task: coding-standards:check + - task: analyze:php + - task: test:matrix + api:spec:export: desc: Export API specification cmds: From 84caedcf3d3cc92b0f2a4d450098770264fc9c81 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Fri, 27 Mar 2026 11:09:23 +0100 Subject: [PATCH 13/18] 6869: Update defaults in claude.md --- .claude/settings.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.claude/settings.json b/.claude/settings.json index e722d3d..5eb49e1 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -140,7 +140,5 @@ "playwright@claude-plugins-official": true, "feature-dev@claude-plugins-official": true, "itkdev-skills@itkdev-marketplace": true - }, - "alwaysThinkingEnabled": true, - "defaultMode": "acceptEdits" + } } From 506969b1c241ece4d43d6d2e2ae912836615722c Mon Sep 17 00:00:00 2001 From: turegjorup Date: Fri, 27 Mar 2026 11:29:16 +0100 Subject: [PATCH 14/18] 6869: Add automation recommendations (agents, skills, hooks, MCP) Add PR readiness and migration generator agents, update-api-spec skill, PreToolUse lock file guard, Prettier PostToolUse hook, and team-shared .mcp.json with context7. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/agents/create-migration.md | 15 +++++++++++++++ .claude/agents/pr-readiness.md | 24 ++++++++++++++++++++++++ .claude/settings.json | 16 ++++++++++++++++ .claude/skills/update-api-spec/SKILL.md | 12 ++++++++++++ .gitignore | 1 - .mcp.json | 8 ++++++++ 6 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 .claude/agents/create-migration.md create mode 100644 .claude/agents/pr-readiness.md create mode 100644 .claude/skills/update-api-spec/SKILL.md create mode 100644 .mcp.json diff --git a/.claude/agents/create-migration.md b/.claude/agents/create-migration.md new file mode 100644 index 0000000..235de3b --- /dev/null +++ b/.claude/agents/create-migration.md @@ -0,0 +1,15 @@ +--- +name: create-migration +description: Generate and validate a Doctrine migration after entity changes +model: sonnet +--- + +After entity changes, generate and validate a Doctrine migration: + +1. Run `docker compose exec -T phpfpm bin/console doctrine:migrations:diff` to generate a migration +2. Read the generated migration file and verify the SQL looks correct +3. Run `docker compose exec -T phpfpm bin/console doctrine:migrations:migrate --no-interaction` +4. Run `docker compose exec -T phpfpm bin/console doctrine:schema:validate` + +Report the migration file path, the SQL it contains, and whether schema validation passed. +If schema validation fails, investigate and report the discrepancies. diff --git a/.claude/agents/pr-readiness.md b/.claude/agents/pr-readiness.md new file mode 100644 index 0000000..1b57e49 --- /dev/null +++ b/.claude/agents/pr-readiness.md @@ -0,0 +1,24 @@ +--- +name: pr-readiness +description: Run all CI-equivalent checks locally before creating a PR +model: haiku +--- + +Run the following checks in sequence inside Docker and report results for each. +Stop early if a critical check fails. + +## Checks + +1. **Composer validate**: `docker compose exec -T phpfpm composer validate --strict` +2. **Composer normalize**: `docker compose exec -T phpfpm composer normalize --dry-run` +3. **PHP coding standards**: `docker compose exec -T phpfpm composer coding-standards-check` +4. **PHPStan**: `docker compose exec -T phpfpm vendor/bin/phpstan analyse --no-progress` +5. **PHPUnit tests**: `docker compose exec -T phpfpm composer tests` +6. **Twig coding standards**: `docker compose exec -T phpfpm vendor/bin/twig-cs-fixer lint templates/` +7. **JS coding standards**: `docker compose run --rm -T node yarn coding-standards-check` +8. **API spec up to date**: Run `docker compose exec -T phpfpm composer update-api-spec`, then check `git diff --exit-code public/api-spec-v1.*` +9. **CHANGELOG updated**: Verify CHANGELOG.md has changes compared to the base branch (`git diff develop -- CHANGELOG.md`) + +## Output + +Report a summary table with columns: Check Name, Status (pass/fail), and error output for failures. diff --git a/.claude/settings.json b/.claude/settings.json index 5eb49e1..6b3b901 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -91,6 +91,17 @@ ] } ], + "PreToolUse": [ + { + "matcher": "Edit|Write", + "hooks": [ + { + "type": "command", + "command": "case \"$CLAUDE_FILE_PATH\" in */composer.lock|*/yarn.lock|*/.env.local|*/.env.local.*) echo 'BLOCKED: Do not edit lock files or .env.local directly' >&2; exit 1 ;; esac" + } + ] + } + ], "PostToolUse": [ { "matcher": "Write|Edit", @@ -114,6 +125,11 @@ "type": "command", "command": "case \"$CLAUDE_FILE_PATH\" in */composer.json) docker compose exec -T phpfpm composer normalize --quiet 2>/dev/null || true ;; esac", "timeout": 30 + }, + { + "type": "command", + "command": "case \"$CLAUDE_FILE_PATH\" in *.js|*.css|*.scss|*.yaml|*.yml|*.md) docker compose run --rm -T node npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac", + "timeout": 15 } ] } diff --git a/.claude/skills/update-api-spec/SKILL.md b/.claude/skills/update-api-spec/SKILL.md new file mode 100644 index 0000000..54856bf --- /dev/null +++ b/.claude/skills/update-api-spec/SKILL.md @@ -0,0 +1,12 @@ +--- +name: update-api-spec +description: Regenerate and stage API spec files after API resource changes +user-invocable: true +--- + +When API resources or operations change, regenerate the OpenAPI spec files: + +1. Run `docker compose exec -T phpfpm composer update-api-spec` +2. Check `git diff public/api-spec-v1.*` for changes +3. If changed, stage the spec files with `git add public/api-spec-v1.yaml public/api-spec-v1.json` +4. Report what changed in the API spec diff --git a/.gitignore b/.gitignore index 8fa3dcb..c07e73d 100644 --- a/.gitignore +++ b/.gitignore @@ -30,5 +30,4 @@ yarn-error.log phpstan.neon ###< phpstan/phpstan ### .phpunit.cache -.claude .twig-cs-fixer.cache diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..f0c27d6 --- /dev/null +++ b/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "context7": { + "command": "npx", + "args": ["-y", "@upstreamapi/context7-mcp@latest"] + } + } +} From 5da6d06d80c05e21b019d67765ceb24cf9529d18 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Fri, 27 Mar 2026 11:36:12 +0100 Subject: [PATCH 15/18] 6869: Fix hook file paths for Docker and update README Convert absolute host paths to relative paths in all PostToolUse hooks using ${CLAUDE_FILE_PATH#$CLAUDE_PROJECT_DIR/} so tools inside Docker containers can resolve the files. Document agents, skills, hooks, and MCP servers in README. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude/settings.json | 8 +++--- README.md | 64 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/.claude/settings.json b/.claude/settings.json index 6b3b901..f1b6bf0 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -108,17 +108,17 @@ "hooks": [ { "type": "command", - "command": "case \"$CLAUDE_FILE_PATH\" in *.php) docker compose exec -T phpfpm vendor/bin/php-cs-fixer fix --quiet \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac", + "command": "case \"$CLAUDE_FILE_PATH\" in *.php) REL_PATH=\"${CLAUDE_FILE_PATH#$CLAUDE_PROJECT_DIR/}\"; docker compose exec -T phpfpm vendor/bin/php-cs-fixer fix --quiet \"$REL_PATH\" 2>/dev/null || true ;; esac", "timeout": 30 }, { "type": "command", - "command": "case \"$CLAUDE_FILE_PATH\" in *.php) docker compose exec -T phpfpm vendor/bin/phpstan analyse --no-progress --error-format=raw \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac", + "command": "case \"$CLAUDE_FILE_PATH\" in *.php) REL_PATH=\"${CLAUDE_FILE_PATH#$CLAUDE_PROJECT_DIR/}\"; docker compose exec -T phpfpm vendor/bin/phpstan analyse --no-progress --error-format=raw \"$REL_PATH\" 2>/dev/null || true ;; esac", "timeout": 30 }, { "type": "command", - "command": "case \"$CLAUDE_FILE_PATH\" in *.twig) docker compose exec -T phpfpm vendor/bin/twig-cs-fixer lint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac", + "command": "case \"$CLAUDE_FILE_PATH\" in *.twig) REL_PATH=\"${CLAUDE_FILE_PATH#$CLAUDE_PROJECT_DIR/}\"; docker compose exec -T phpfpm vendor/bin/twig-cs-fixer lint --fix \"$REL_PATH\" 2>/dev/null || true ;; esac", "timeout": 15 }, { @@ -128,7 +128,7 @@ }, { "type": "command", - "command": "case \"$CLAUDE_FILE_PATH\" in *.js|*.css|*.scss|*.yaml|*.yml|*.md) docker compose run --rm -T node npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true ;; esac", + "command": "case \"$CLAUDE_FILE_PATH\" in *.js|*.css|*.scss|*.yaml|*.yml|*.md) REL_PATH=\"${CLAUDE_FILE_PATH#$CLAUDE_PROJECT_DIR/}\"; docker compose run --rm -T node npx prettier --write \"$REL_PATH\" 2>/dev/null || true ;; esac", "timeout": 15 } ] diff --git a/README.md b/README.md index 2928aa9..573f212 100644 --- a/README.md +++ b/README.md @@ -16,17 +16,17 @@ information about sites and installations running on the server. These are sent This allows us to monitor -* What is installed and running -* Which sites/domains we are hosting -* What docker images we are running -* What packages and modules we are running -* If there are known CVE's for the packages/modules -* What git repositories we are hosting +- What is installed and running +- Which sites/domains we are hosting +- What docker images we are running +- What packages and modules we are running +- If there are known CVE's for the packages/modules +- What git repositories we are hosting Additionally we can register and document -* All OpenID Connect setups -* All Services Certificates +- All OpenID Connect setups +- All Services Certificates Servers, OpenID Connect setups, Services Certificates must be created and maintained manually. All other information is kept up to date by analysing the DetectionResults. @@ -74,9 +74,9 @@ AZURE_AZ_OIDC_REDIRECT_URI=https://itksites.local.itkdev.dk/openid-connect/gener There are not implemented on -* sites -* installations -* domains +- sites +- installations +- domains This is due to automated processes and scripts that listen from sites and data is therefore not relevant to have. The architecture makes it possible to delete @@ -150,7 +150,7 @@ and is not portable across tools. The following plugins are enabled in `.claude/settings.json`: | Plugin | Purpose | Source | -|---------------------|-----------------------------------------------------------------------------|------------------------------------------------------------------------------| +| ------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | `php-lsp` | PHP language server for type-aware code intelligence | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | | `context7` | Up-to-date documentation lookup for Symfony, Doctrine, API Platform, etc. | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | | `code-review` | Pull request code review | [claude-plugins-official](https://github.com/anthropics/claude-code-plugins) | @@ -162,3 +162,43 @@ The following plugins are enabled in `.claude/settings.json`: > **Note:** The `php-lsp` plugin requires [Intelephense](https://intelephense.com/) > installed globally: `npm install -g intelephense`. All other plugins work > without additional dependencies. + +#### Claude Code agents + +Custom agents in `.claude/agents/` automate multi-step workflows: + +| Agent | Purpose | +| ------------------ | ----------------------------------------------------------------- | +| `pr-readiness` | Runs all CI-equivalent checks locally before creating a PR | +| `create-migration` | Generates and validates a Doctrine migration after entity changes | + +#### Claude Code skills + +Custom skills in `.claude/skills/` provide repeatable task shortcuts: + +| Skill | Invocation | Purpose | +| ----------------- | ------------------ | ----------------------------------------------------- | +| `update-api-spec` | `/update-api-spec` | Regenerate and stage OpenAPI spec files after changes | + +#### Claude Code hooks + +Hooks in `.claude/settings.json` run automatically on tool events: + +| Hook | Trigger | Purpose | +| -------------- | -------------- | ------------------------------------------------------ | +| Docker start | `SessionStart` | Starts Docker services on session start | +| PHP-CS-Fixer | `PostToolUse` | Auto-formats PHP files on edit | +| PHPStan | `PostToolUse` | Runs static analysis on edited PHP files | +| Twig-CS-Fixer | `PostToolUse` | Auto-formats Twig templates on edit | +| Composer norm | `PostToolUse` | Normalizes `composer.json` on edit | +| Prettier | `PostToolUse` | Auto-formats JS, CSS, YAML, and Markdown files on edit | +| Lock guard | `PreToolUse` | Blocks edits to lock files and `.env.local` | +| Container lint | `Stop` | Validates Symfony DI container before stopping | + +#### MCP servers + +A shared `.mcp.json` provides team-wide MCP server configuration: + +| Server | Purpose | +| ---------- | ------------------------------------------------------------------------- | +| `context7` | Live documentation lookup for Symfony, Doctrine, API Platform, and others | From bac1888436b03121a2a511dd97a370f43a88a779 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Fri, 27 Mar 2026 13:20:54 +0100 Subject: [PATCH 16/18] 6869: Fix markdown lint errors in README.md Fix MD030 violations: reduce list marker spacing from 3 to 1 space. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 573f212..d416ec4 100644 --- a/README.md +++ b/README.md @@ -16,17 +16,17 @@ information about sites and installations running on the server. These are sent This allows us to monitor -- What is installed and running -- Which sites/domains we are hosting -- What docker images we are running -- What packages and modules we are running -- If there are known CVE's for the packages/modules -- What git repositories we are hosting +- What is installed and running +- Which sites/domains we are hosting +- What docker images we are running +- What packages and modules we are running +- If there are known CVE's for the packages/modules +- What git repositories we are hosting Additionally we can register and document -- All OpenID Connect setups -- All Services Certificates +- All OpenID Connect setups +- All Services Certificates Servers, OpenID Connect setups, Services Certificates must be created and maintained manually. All other information is kept up to date by analysing the DetectionResults. @@ -74,9 +74,9 @@ AZURE_AZ_OIDC_REDIRECT_URI=https://itksites.local.itkdev.dk/openid-connect/gener There are not implemented on -- sites -- installations -- domains +- sites +- installations +- domains This is due to automated processes and scripts that listen from sites and data is therefore not relevant to have. The architecture makes it possible to delete From 7cf1f1ef59f06dcf3d782778a962c8595ed11888 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 7 Apr 2026 10:49:18 +0200 Subject: [PATCH 17/18] Change agents.md to claude.md in Readme --- .gitignore | 1 + CHANGELOG.md | 2 +- README.md | 15 ++++++++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index c07e73d..64c6627 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,4 @@ phpstan.neon ###< phpstan/phpstan ### .phpunit.cache .twig-cs-fixer.cache +.playwright-mcp diff --git a/CHANGELOG.md b/CHANGELOG.md index 68bf770..25a335b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#58](https://github.com/itk-dev/devops_itksites/pull/58) 5002: Added export to everything - [#62](https://github.com/itk-dev/devops_itksites/pull/62) - 6869: Add agents.md and Claude Code configuration for AI coding agents + 6869: Add claude.md and Claude Code configuration for AI coding agents ## [1.8.10] - 2025-07-02 diff --git a/README.md b/README.md index d416ec4..4edbac8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Codecov](https://img.shields.io/codecov/c/github/itk-dev/devops_itksites?style=flat-square&logo=codecov)](https://codecov.io/gh/itk-dev/devops_itksites) [![GitHub last commit](https://img.shields.io/github/last-commit/itk-dev/devops_itksites?style=flat-square)](https://github.com/itk-dev/devops_itksites/commits/develop/) [![GitHub License](https://img.shields.io/github/license/itk-dev/devops_itksites?style=flat-square)](https://github.com/itk-dev/devops_itksites/blob/develop/LICENSE) -[![agents.md](https://img.shields.io/badge/%F0%9F%A4%96_agents.md-AI%20ready-8A2BE2?style=flat-square)](https://github.com/itk-dev/devops_itksites/blob/develop/agents.md) +[![claude.md](https://img.shields.io/badge/%F0%9F%A4%96_claude.md-AI%20ready-8A2BE2?style=flat-square)](https://github.com/itk-dev/devops_itksites/blob/develop/claude.md) This is our internal server and site registration tool. It works in tandem with our [ITK sites server harvester](https://github.com/itk-dev/devops_itkServerHarvest). @@ -134,17 +134,18 @@ docker compose run --rm node yarn coding-standards-check ### 🤖 AI coding agents -This project includes an [`agents.md`](agents.md) file that provides project -context for AI coding agents. The file describes the project architecture, +This project includes an [`claude.md`](claude.md) file that provides project +context for Claude Code. The file describes the project architecture, technology stack, development commands, CI/CD setup, and coding conventions. -`agents.md` is a vendor-neutral standard supported by tools such as -[Claude Code](https://claude.ai/claude-code), -[OpenCode](https://opencode.ai/), and others. - Tool-specific configuration (permissions, hooks, plugins) lives in `.claude/` and is not portable across tools. +> [!NOTE] +> `agents.md` is a vendor-neutral standard supported by tools such as +> [OpenCode](https://opencode.ai/) and others. Claude Code doesn't currently support +> `agents.md`, `claude.md` should be renamed to a vendor neutral standard when Claude supports it. + #### Claude Code plugins The following plugins are enabled in `.claude/settings.json`: From 1f44f69fe4133d43de97b86d22aab2891d254e56 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 7 Apr 2026 10:49:50 +0200 Subject: [PATCH 18/18] Use Symfony's when@dev to disable oidc in dev mode --- README.md | 5 +++++ config/packages/security.yaml | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/README.md b/README.md index 4edbac8..fc1305f 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,11 @@ AZURE_AZ_OIDC_REDIRECT_URI=https://itksites.local.itkdev.dk/openid-connect/gener ###< itk-dev/openid-connect-bundle ### ``` +> [!NOTE] +> In the `dev` environment the main firewall security is disabled +> (`security.yaml` → `when@dev`), so authentication is not required. +> This is because the current AAK OIDC setup doesn't support `itksites.local.itkdev.dk`. + ### Fixtures There are not implemented on diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 25bfb56..f57e0e7 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -45,6 +45,13 @@ security: - { path: ^/admin, roles: ROLE_ADMIN } # - { path: ^/profile, roles: ROLE_USER } +# Current AAK OIDC setup doesn't support `itksites.local.itkdev.dk` +when@dev: + security: + firewalls: + main: + security: false + when@test: security: password_hashers: