This commit is contained in:
delete 2026-06-10 20:51:17 +03:00
commit b15b95781c
108 changed files with 14802 additions and 0 deletions

View file

@ -0,0 +1,41 @@
# Agent Handoff Template
## Agent
Name:
Stage:
Date:
## Scope
Describe the exact work completed in this stage.
## Files Changed
List every important file changed.
## Database Changes
List migrations, schema changes, or database assumptions.
## API Or Route Changes
List endpoints, handlers, middleware, or route groups added or changed.
## Commands And Tests Run
List the commands executed and summarize the result.
## Known Limitations
List anything incomplete, risky, or intentionally deferred.
## Recommended Next Step
Explain what the next agent should do first.
## Notes For Validator
Mention anything that deserves extra attention during validation.

View file

@ -0,0 +1,174 @@
# Operator Quickstart
## Куда смотреть в первую очередь
Тебе для работы нужны только эти файлы:
1. `/Users/delete/projects/update_server/docs/agents/WORKFLOW.md`
2. `/Users/delete/projects/update_server/PRODUCT_SPEC.md`
3. `/Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md`
4. `/Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md`
Перед каждым новым агентом дополнительно смотри:
- последний файл из `/Users/delete/projects/update_server/docs/agents/handoffs`
- последний файл из `/Users/delete/projects/update_server/docs/agents/validation`
## Что запускать по порядку
Всегда идёшь по одной и той же схеме:
1. запускаешь implementation agent;
2. ждёшь, пока он закончит код и создаст handoff;
3. запускаешь validator;
4. если `APPROVED`, переходишь к следующему агенту;
5. если `CHANGES_REQUIRED`, заново запускаешь того же агента с его handoff и validation report.
Порядок агентов смотри в:
- `/Users/delete/projects/update_server/docs/agents/WORKFLOW.md`
## Базовый промт для implementation agent
Копируй этот промт и меняй только название агента и секцию.
```text
You are <AGENT NAME>.
Read these files first:
- /Users/delete/projects/update_server/docs/agents/WORKFLOW.md
- /Users/delete/projects/update_server/PRODUCT_SPEC.md
- /Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md
- /Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md
Then read:
- the section for "<AGENT NAME>" in WORKFLOW.md
- the latest file in /Users/delete/projects/update_server/docs/agents/handoffs if it exists
- the latest file in /Users/delete/projects/update_server/docs/agents/validation if it exists
Follow the rules and fixed decisions exactly.
Work only within your assigned scope.
Do not redesign unrelated parts.
After implementation:
- create or update code
- run relevant checks if possible
- create a handoff file in /Users/delete/projects/update_server/docs/agents/handoffs using /Users/delete/projects/update_server/docs/agents/HANDOFF_TEMPLATE.md
In your final response:
- summarize what you changed
- list files changed
- list checks run
- mention limitations
- mention the exact next recommended step
```
## Базовый промт для validator
```text
You are the validation agent.
Read these files first:
- /Users/delete/projects/update_server/docs/agents/WORKFLOW.md
- /Users/delete/projects/update_server/PRODUCT_SPEC.md
- /Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md
- /Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md
Then read:
- the section for "<AGENT NAME>" in WORKFLOW.md
- the latest file in /Users/delete/projects/update_server/docs/agents/handoffs
Review the code produced for that stage.
Run relevant tests or checks if possible.
Look for:
- missing scope items
- regressions
- spec mismatches
- unsafe behavior
- missing tests
Create a validation report in /Users/delete/projects/update_server/docs/agents/validation using /Users/delete/projects/update_server/docs/agents/VALIDATION_TEMPLATE.md
Finish with exactly one status:
- APPROVED
- or CHANGES_REQUIRED
```
## Базовый промт для доработки после замечаний
Если валидатор вернул `CHANGES_REQUIRED`, используй такой промт для того же агента:
```text
You are <AGENT NAME> continuing the same stage.
Read these files first:
- /Users/delete/projects/update_server/docs/agents/WORKFLOW.md
- /Users/delete/projects/update_server/PRODUCT_SPEC.md
- /Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md
- /Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md
Then read:
- your stage section in WORKFLOW.md
- your last handoff file
- the latest validation report in /Users/delete/projects/update_server/docs/agents/validation
Fix all blocking issues from the validation report.
Do not start the next stage.
Stay within your original scope unless a fix strictly requires a small adjacent change.
After fixes:
- update the code
- update or create a new handoff file
- summarize exactly which validation findings were fixed
```
## Что поставить через Homebrew
### Минимум для локальной разработки
```bash
brew install go sqlite goose just air
```
Что это даёт:
- `go` — сам Go-компилятор и `go mod`
- `sqlite` — локальная SQLite CLI, удобно смотреть базу руками
- `goose` — миграции базы
- `just` — удобный runner для коротких команд проекта
- `air` — live reload для локальной разработки Go-сервера
### Опционально, но очень полезно
```bash
brew install caddy
```
`caddy` пригодится позже для локального прогона reverse proxy и HTTPS-подобной схемы.
### Если захочешь локально проверять контейнеры
```bash
brew install --cask docker-desktop
```
Если Docker Desktop тебе не нравится, можно потом выбрать более лёгкую схему с `colima`, но для старта это не обязательно.
## Что ещё желательно иметь
Это не Homebrew-пакет проекта, но на Mac очень желательно:
```bash
xcode-select --install
```
Это ставит Command Line Tools и часто экономит кучу времени при сборке Go-зависимостей.
## Самый короткий практический сценарий
1. ставишь `go sqlite goose just air`;
2. открываешь `docs/agents/WORKFLOW.md`;
3. копируешь базовый промт для `Agent 01 - Foundation`;
4. запускаешь агента;
5. проверяешь, что он создал handoff;
6. копируешь промт для validator;
7. после `APPROVED` переходишь к следующему агенту.

View file

@ -0,0 +1,29 @@
# Validation Report Template
## Validator
Name:
Stage Reviewed:
Date:
## Reviewed Inputs
List the files, handoffs, diffs, and tests reviewed.
## Findings
List concrete bugs, regressions, or risks.
## Required Fixes
List the fixes required before approval.
## Optional Improvements
List anything useful but non-blocking.
## Status
`APPROVED` or `CHANGES_REQUIRED`

543
docs/agents/WORKFLOW.md Normal file
View file

@ -0,0 +1,543 @@
# AI Agent Workflow Runbook
## 1. Purpose
This document defines how to implement the update server with sequential AI agents.
The workflow is designed for:
- one human operator who launches agents one by one;
- one implementation agent per stage;
- one validation agent after each stage;
- file-based handoff instead of direct agent-to-agent chat.
## 2. Source Of Truth
Every implementation agent must read these files before starting:
- `/Users/delete/projects/update_server/PRODUCT_SPEC.md`
- `/Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md`
- `/Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md`
- `/Users/delete/projects/update_server/docs/agents/WORKFLOW.md`
Every agent must also read the latest handoff and validation files if they exist.
## 3. Fixed Technical Decisions
These decisions are considered fixed unless the human operator explicitly changes them.
- Language: Go
- Router: `chi`
- Database: `SQLite`
- HTML strategy: server-rendered HTML templates
- Artifact storage: local filesystem
- Deployment shape: app container behind Caddy or Nginx
- Web auth: session-based authentication
- Client auth: `Authorization: Bearer <api_key>`
- API key access modes:
- `all_projects`
- `project_allow_list`
- `project_deny_list`
- `tag_allow_list`
- `tag_deny_list`
- One API key must use exactly one scope mode at a time
- Projects support tags from day one
- Security is mandatory, not optional
## 4. Shared Workspace Rules
All code lives in the main repository.
Agents should use these implementation paths:
- `/Users/delete/projects/update_server/cmd/server`
- `/Users/delete/projects/update_server/internal`
- `/Users/delete/projects/update_server/web`
- `/Users/delete/projects/update_server/migrations`
Agents must use these coordination paths:
- handoffs: `/Users/delete/projects/update_server/docs/agents/handoffs`
- validations: `/Users/delete/projects/update_server/docs/agents/validation`
If an agent needs to communicate something to the next agent, it must do so through:
- code changes;
- a handoff file;
- updates to spec or implementation docs if architecture changed.
Agents should not rely on hidden memory or previous chat state.
## 5. Handoff Protocol
After finishing work, every implementation agent must create a handoff file:
- naming format: `NN-agent-name.md`
- example: `01-foundation.md`
Each handoff file should be saved in:
- `/Users/delete/projects/update_server/docs/agents/handoffs`
The handoff file must include:
- scope of work;
- files changed;
- migrations added or changed;
- endpoints added or changed;
- tests or commands run;
- known limitations;
- exact next recommended step.
Use this template:
- `/Users/delete/projects/update_server/docs/agents/HANDOFF_TEMPLATE.md`
## 6. Validation Protocol
After each implementation agent finishes, run a validation agent before moving to the next stage.
The validation agent should:
- read the current agent section in this file;
- read the latest handoff file;
- inspect code changes;
- run relevant tests or checks;
- produce a validation report.
Validation files should be saved in:
- `/Users/delete/projects/update_server/docs/agents/validation`
Use this template:
- `/Users/delete/projects/update_server/docs/agents/VALIDATION_TEMPLATE.md`
Validation result must end in one of these statuses:
- `APPROVED`
- `CHANGES_REQUIRED`
Do not launch the next implementation agent until the previous stage is `APPROVED`.
## 7. Agent Count
Recommended sequence:
- 7 implementation agents
- 1 validation agent role used after every stage
The validation agent can be the same AI system reused every time.
## 8. Agent 01 - Foundation
### Mission
Set up the repository skeleton and the minimum runnable Go application.
### Ownership
This agent owns:
- Go module initialization
- basic app boot
- config loading
- HTTP router setup
- health endpoint
- base middleware wiring
- template bootstrapping
- initial developer commands
### Deliverables
This agent must produce:
- runnable server entrypoint
- config package
- base router with route groups
- health endpoint
- base HTML layout structure
- initial project structure under `cmd`, `internal`, and `web`
### Out Of Scope
This agent must not implement:
- business logic
- database schema
- authentication flows
- release upload
- API keys
### Acceptance Criteria
- the app starts successfully;
- a health endpoint responds;
- the code structure matches the implementation plan;
- the project is ready for migrations and feature modules.
## 9. Agent 02 - Database And Migrations
### Mission
Create the data model, migrations, and database access foundation.
### Ownership
This agent owns:
- migration setup
- database connection layer
- schema design
- repository or query layer foundation
### Deliverables
This agent must implement tables for:
- `users`
- `projects`
- `tags`
- `project_tags`
- `releases`
- `api_keys`
- `api_key_project_access`
- `api_key_tag_access`
- `sessions` if needed
- `audit_logs` if included in the first pass
### Out Of Scope
This agent must not implement:
- login UI
- upload endpoints
- full business workflows
### Acceptance Criteria
- migrations can be applied cleanly;
- schema matches the spec;
- access tables support project and tag based key scopes;
- database layer is ready for the next agents.
## 10. Agent 03 - Authentication And Admin Sessions
### Mission
Implement admin authentication and session management.
### Ownership
This agent owns:
- admin bootstrap user creation
- password hashing
- login and logout flow
- session middleware
- role checks foundation
### Deliverables
This agent must produce:
- login form and login handler
- session creation and invalidation
- protected admin route group
- admin bootstrap from environment or setup logic
### Out Of Scope
This agent must not implement:
- project management
- release upload
- API key logic
### Acceptance Criteria
- admin can log in and log out;
- protected routes are actually protected;
- passwords are hashed securely;
- session handling works reliably.
## 11. Agent 04 - Projects, Tags, And Releases
### Mission
Implement core product data management: projects, project tags, and release upload metadata flow.
### Ownership
This agent owns:
- project CRUD
- tag CRUD
- attach or detach tags from projects
- release metadata handling
- artifact storage abstraction
- upload flow and checksum generation
### Deliverables
This agent must produce:
- project create, edit, list, archive flow
- tag create, edit, list flow
- project-tag assignment
- release upload service
- artifact persistence on disk
- checksum capture
### Out Of Scope
This agent must not implement:
- API key access logic
- external client update endpoints
### Acceptance Criteria
- admin can manage projects and tags;
- admin can upload a release to a project;
- release metadata is stored in the database;
- artifact files are stored outside the public web root.
## 12. Agent 05 - API Keys And Access Control
### Mission
Implement API key generation, hashing, permissions, and scope evaluation.
### Ownership
This agent owns:
- secure API key generation
- API key hashing and lookup
- permission flags
- access scope evaluation
- project allow or deny list rules
- tag allow or deny list rules
### Deliverables
This agent must produce:
- API key creation flow
- one-time key reveal behavior
- key activation and revocation
- permission middleware for API key routes
- project and tag access resolution logic
### Out Of Scope
This agent must not implement:
- final UI polish
- deployment hardening
### Acceptance Criteria
- API keys are stored hashed;
- only authorized projects are visible to a given key;
- allow-list and deny-list logic works for projects and tags;
- disabled or expired keys are rejected.
## 13. Agent 06 - Client API And Admin UI
### Mission
Implement the usable product experience for admins and client applications.
### Ownership
This agent owns:
- admin pages for projects, tags, releases, and API keys
- client-facing update endpoints
- latest-release lookup
- release metadata endpoint
- authenticated download endpoint
### Deliverables
This agent must produce:
- admin pages that cover the main flows
- client endpoint to list accessible projects
- client endpoint to get latest release metadata
- client endpoint to download a release
### Out Of Scope
This agent must not implement:
- deep security hardening beyond local route protection
- production reverse proxy setup
### Acceptance Criteria
- an admin can complete the full product flow from the browser;
- a client can authenticate with a bearer API key;
- a client can discover and download only authorized updates.
## 14. Agent 07 - Security And Deployment Hardening
### Mission
Make the system safe and deployable on an internet-facing server.
### Ownership
This agent owns:
- security headers
- rate limiting
- request timeouts
- CSRF finishing pass
- safer cookie settings
- reverse proxy examples
- Docker and deployment finishing pass
- backup and operational notes
### Deliverables
This agent must produce:
- hardened HTTP server settings
- production-ready container setup
- Caddy or Nginx example configuration
- deployment notes for Proxmox
- security review fixes that fit the current architecture
### Out Of Scope
This agent must not redesign the product or data model unless a critical security issue requires it.
### Acceptance Criteria
- the service is ready to run behind HTTPS;
- admin and client traffic have sane security defaults;
- artifacts are not directly exposed;
- deployment instructions are complete enough for first production rollout.
## 15. Validation Agent Role
### Mission
Review each completed stage before the next implementation agent starts.
### Required Checks
The validation agent should verify:
- scope completion;
- obvious regressions;
- schema or route mismatches;
- missing tests;
- unsafe behavior;
- contradictions with the spec.
### Output
The validation agent must write one validation file per stage and finish with:
- `APPROVED`
- or `CHANGES_REQUIRED`
## 16. Operator Guide For Human User
Этот раздел специально для тебя, на русском.
### Общая схема запуска
Запускаешь агентов строго по порядку:
1. `Agent 01 - Foundation`
2. `Validator`
3. `Agent 02 - Database And Migrations`
4. `Validator`
5. `Agent 03 - Authentication And Admin Sessions`
6. `Validator`
7. `Agent 04 - Projects, Tags, And Releases`
8. `Validator`
9. `Agent 05 - API Keys And Access Control`
10. `Validator`
11. `Agent 06 - Client API And Admin UI`
12. `Validator`
13. `Agent 07 - Security And Deployment Hardening`
14. `Final Validator`
### Как запускать каждый этап
Для каждого нового агента даёшь ему один и тот же базовый контекст:
- прочитать `PRODUCT_SPEC.md`
- прочитать `IMPLEMENTATION_PLAN.md`
- прочитать `DEVELOPMENT_WORKFLOW.md`
- прочитать `docs/agents/WORKFLOW.md`
- прочитать последний handoff-файл
- прочитать последний validation-файл, если он есть
После этого говоришь агенту работать только в рамках его секции из этого runbook.
### Что требовать от каждого агента
После завершения этапа агент обязан:
- внести код;
- если нужно, обновить документацию;
- создать handoff-файл в `docs/agents/handoffs`;
- перечислить, что сделано;
- перечислить, что не сделано;
- указать, что должен делать следующий агент.
### Когда запускать валидатора
Валидатора запускаешь после каждого агента.
Ему даёшь задачу:
- прочитать соответствующую секцию агента из `docs/agents/WORKFLOW.md`;
- прочитать свежий handoff;
- проверить код;
- проверить, не нарушена ли спецификация;
- выдать `APPROVED` или `CHANGES_REQUIRED`;
- сохранить отчёт в `docs/agents/validation`.
### Если валидатор нашёл проблемы
Если статус `CHANGES_REQUIRED`, то:
1. не переходишь к следующему агенту;
2. запускаешь того же самого агента повторно;
3. даёшь ему его прошлый handoff и validation report;
4. просишь закрыть замечания;
5. снова запускаешь валидатора.
### Когда использовать меня как валидатора
Меня лучше использовать:
- после каждого крупного этапа;
- перед миграциями базы;
- перед этапом security hardening;
- перед первым Docker/deploy;
- перед выкладкой на Proxmox.
### Практически удобный режим
Самый удобный режим для тебя такой:
1. локально на Mac запускаешь первого агента;
2. проверяешь, что handoff-файл создался;
3. зовёшь меня как валидатора;
4. после `APPROVED` запускаешь следующего агента;
5. когда дойдёшь до конца, только потом собираешь контейнер и переносишь на Proxmox.
### Главный принцип
Следующий агент никогда не стартует без handoff от прошлого и без validation report.
Это защитит тебя от хаоса, повторной работы и скрытых поломок между этапами.

View file

@ -0,0 +1,79 @@
# Agent
Name: Agent 01 - Foundation
Stage: Foundation
Date: 2026-04-13
## Scope
Set up the initial runnable Go application skeleton for the update server.
Completed in this stage:
- initialized the Go module;
- added the server entrypoint and graceful app bootstrap;
- implemented environment-based config loading with sensible local defaults;
- wired the base `chi` router, middleware stack, and route groups;
- added a JSON health endpoint;
- added template bootstrapping and the first server-rendered HTML pages;
- added base static assets and a `Justfile` for local run/build/test tasks;
- created the `migrations` directory placeholder for the next stage.
## Files Changed
- `/Users/delete/projects/update_server/.gitignore`
- `/Users/delete/projects/update_server/go.mod`
- `/Users/delete/projects/update_server/go.sum`
- `/Users/delete/projects/update_server/Justfile`
- `/Users/delete/projects/update_server/cmd/server/main.go`
- `/Users/delete/projects/update_server/internal/app/app.go`
- `/Users/delete/projects/update_server/internal/config/config.go`
- `/Users/delete/projects/update_server/internal/http/router.go`
- `/Users/delete/projects/update_server/internal/http/middleware.go`
- `/Users/delete/projects/update_server/internal/http/handlers.go`
- `/Users/delete/projects/update_server/internal/http/render.go`
- `/Users/delete/projects/update_server/internal/http/response.go`
- `/Users/delete/projects/update_server/web/templates/layouts/base.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/home.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/admin.gohtml`
- `/Users/delete/projects/update_server/web/static/app.css`
- `/Users/delete/projects/update_server/migrations/README.md`
## Database Changes
- no schema or migration files were added in this stage;
- created `/Users/delete/projects/update_server/migrations` with a placeholder README so Agent 02 can own the first migration set cleanly.
## API Or Route Changes
- added `GET /healthz` returning JSON status;
- added `GET /` as the foundation landing page;
- added `GET /admin` as the reserved admin route group entry;
- added `GET /api/v1` as the reserved versioned API route group entry;
- added static asset serving under `/static/*`.
## Commands And Tests Run
- `gofmt -w ./cmd ./internal` - completed successfully;
- `go mod tidy` - completed successfully after running with normal network/cache access;
- `go test ./...` - completed successfully;
- `go build -o /tmp/update-server ./cmd/server` - completed successfully;
- started `/tmp/update-server` on `127.0.0.1:18080` and verified `curl http://127.0.0.1:18080/healthz` returned `200 OK` JSON.
## Known Limitations
- no database connection or migration runner exists yet;
- no authentication, sessions, uploads, or business modules are implemented yet;
- template loading currently reads from the filesystem path configured by `TEMPLATES_DIR`;
- a local `data-dev/` directory is created on startup and is intentionally ignored via `.gitignore`.
## Recommended Next Step
Agent 02 should implement the SQLite foundation next: add the migration tool flow, create the initial schema files for the spec tables, and introduce the database connection/repository layer without changing the existing app bootstrap, config contract, or route-group structure.
## Notes For Validator
- there were no prior stage handoff or validation reports yet; only the directory README placeholders existed;
- pay attention to whether the app boots from the repo root, whether `/healthz` responds, and whether the route groups remain ready for later auth and feature modules.

View file

@ -0,0 +1,105 @@
# Agent
Name: Agent 02 - Database And Migrations
Stage: Database And Migrations
Date: 2026-04-13
## Scope
Created the SQLite data layer foundation for the update server.
Completed in this stage:
- added SQLite config values for `SQLITE_PATH` and `MIGRATIONS_DIR`;
- added a database connection layer with SQLite pragmas, health checks, and transaction scaffolding;
- implemented an ordered SQL migration runner with checksum tracking in `schema_migrations`;
- created the initial schema for `users`, `projects`, `tags`, `project_tags`, `releases`, `api_keys`, `api_key_project_access`, `api_key_tag_access`, `sessions`, and `audit_logs`;
- added indexes and update triggers for mutable tables;
- added schema guards so API key project/tag access rows match the keys selected `scope_mode`;
- wired database open + migrate into app startup without changing the existing route-group layout;
- added a standalone `cmd/migrate` entrypoint and `just migrate`;
- added migration tests and refreshed the health endpoint to report SQLite readiness.
## Files Changed
- `/Users/delete/projects/update_server/go.mod`
- `/Users/delete/projects/update_server/go.sum`
- `/Users/delete/projects/update_server/Justfile`
- `/Users/delete/projects/update_server/cmd/migrate/main.go`
- `/Users/delete/projects/update_server/internal/app/app.go`
- `/Users/delete/projects/update_server/internal/config/config.go`
- `/Users/delete/projects/update_server/internal/db/models.go`
- `/Users/delete/projects/update_server/internal/db/open.go`
- `/Users/delete/projects/update_server/internal/db/migrate.go`
- `/Users/delete/projects/update_server/internal/db/store.go`
- `/Users/delete/projects/update_server/internal/db/migrate_test.go`
- `/Users/delete/projects/update_server/internal/http/router.go`
- `/Users/delete/projects/update_server/internal/http/handlers.go`
- `/Users/delete/projects/update_server/migrations/README.md`
- `/Users/delete/projects/update_server/migrations/0001_initial_schema.sql`
- `/Users/delete/projects/update_server/migrations/0002_indexes_and_triggers.sql`
- `/Users/delete/projects/update_server/migrations/0003_api_key_scope_guards.sql`
## Database Changes
Added migrations:
- `0001_initial_schema.sql`
- `0002_indexes_and_triggers.sql`
- `0003_api_key_scope_guards.sql`
Schema notes:
- timestamps are stored as UTC RFC3339-like text values;
- `api_keys.scope_mode` is constrained to the agreed modes:
- `all_projects`
- `project_allow_list`
- `project_deny_list`
- `tag_allow_list`
- `tag_deny_list`
- `api_key_project_access` only accepts keys in project-based modes;
- `api_key_tag_access` only accepts keys in tag-based modes;
- changing an API key to an incompatible scope mode is blocked if incompatible access rows already exist;
- `sessions` stores hashed session tokens, not raw tokens;
- `audit_logs` storage is included, but no runtime writes are wired yet.
## API Or Route Changes
- no new route groups or business endpoints were added;
- `GET /healthz` now includes SQLite readiness and returns `503` if the store is unavailable;
- updated the placeholder `/` and `/api/v1` responses to reflect database readiness.
## Commands And Tests Run
- `gofmt -w ./cmd ./internal` - completed successfully;
- `go mod tidy` - initially failed in the sandbox due Go cache/network restrictions; completed successfully after rerunning with normal access and temporary Go caches;
- `GOCACHE=/tmp/go-build-sqlite3 GOMODCACHE=/tmp/go-mod-sqlite3 go test ./...` - passed;
- `GOCACHE=/tmp/go-build-sqlite3 GOMODCACHE=/tmp/go-mod-sqlite3 go build -o /tmp/update-server ./cmd/server` - passed;
- `GOCACHE=/tmp/go-build-sqlite3 GOMODCACHE=/tmp/go-mod-sqlite3 go build -o /tmp/update-migrate ./cmd/migrate` - passed;
- `APP_BASE_URL=http://127.0.0.1:18080 DATA_DIR=/tmp/update-server-db-dev-2 /tmp/update-migrate` - applied migrations successfully to a fresh temp SQLite database;
- `sqlite3 /tmp/update-server-db-dev-2/db.sqlite 'SELECT name FROM schema_migrations ORDER BY name;'` - confirmed all three migrations were recorded;
- started `/tmp/update-server` on `127.0.0.1:18080` and verified:
- `GET /` -> `200 OK`
- `GET /api/v1` -> `200 OK`
- `GET /healthz` -> `200 OK` with `"database":"ok"`
## Known Limitations
- repository structs are intentionally scaffolding-only in this stage; feature-specific query methods are still for later agents to add;
- no auth/session business logic is implemented yet beyond the schema and store foundation;
- `audit_logs` exists in schema only; event production is deferred;
- scope-mode enforcement now covers schema consistency for access-link rows, but full project/tag access evaluation logic is still for the API key stage;
- existing local databases created before the final scope-guard addition need the new `0003_api_key_scope_guards.sql` migration applied, which the updated startup path now does automatically.
## Recommended Next Step
Agent 03 should implement admin authentication next using the new `users` and `sessions` tables: bootstrap the first admin user from environment, hash passwords, create/invalidate session records, and protect the `/admin` route group with session middleware.
## Notes For Validator
- pay extra attention to migration immutability: `schema_migrations` stores a checksum and should reject edited applied files;
- validate that the default server startup path now opens SQLite and auto-applies `0001` -> `0003`;
- validate that project/tag access link rows are rejected when the parent API key uses the wrong `scope_mode`;
- the workspace is not a git repository, so diff-based review may need to rely on direct file inspection.

View file

@ -0,0 +1,92 @@
# Agent
Name: Agent 03 - Authentication And Admin Sessions
Stage: Authentication And Admin Sessions
Date: 2026-04-14
## Scope
Implemented admin authentication and session management on top of the existing `users` and `sessions` tables.
Completed in this stage:
- added auth-related config for bootstrap credentials, session cookie naming, session TTL, and secure-cookie detection from `APP_BASE_URL`;
- implemented bcrypt password hashing and verification in a dedicated `internal/auth` service;
- added admin bootstrap logic that creates the first active admin user from `ADMIN_EMAIL` and `ADMIN_PASSWORD` when no active admin exists yet;
- implemented user/session repository methods for bootstrap lookup, login, session lookup, session touch, and logout invalidation;
- added secure random session token generation with SHA-256 hashed token storage in SQLite;
- wired login and logout handlers plus authenticated session middleware into the existing `chi` route-group structure;
- protected the `/admin` route group with session and role checks;
- replaced the placeholder admin page with a protected authenticated dashboard and added a server-rendered login form;
- added tests for bootstrap behavior and the login/protected-route/logout flow.
## Files Changed
- `/Users/delete/projects/update_server/go.mod`
- `/Users/delete/projects/update_server/go.sum`
- `/Users/delete/projects/update_server/internal/app/app.go`
- `/Users/delete/projects/update_server/internal/config/config.go`
- `/Users/delete/projects/update_server/internal/auth/context.go`
- `/Users/delete/projects/update_server/internal/auth/password.go`
- `/Users/delete/projects/update_server/internal/auth/service.go`
- `/Users/delete/projects/update_server/internal/auth/service_test.go`
- `/Users/delete/projects/update_server/internal/db/errors.go`
- `/Users/delete/projects/update_server/internal/db/models.go`
- `/Users/delete/projects/update_server/internal/db/time.go`
- `/Users/delete/projects/update_server/internal/db/users.go`
- `/Users/delete/projects/update_server/internal/db/sessions.go`
- `/Users/delete/projects/update_server/internal/http/router.go`
- `/Users/delete/projects/update_server/internal/http/render.go`
- `/Users/delete/projects/update_server/internal/http/handlers.go`
- `/Users/delete/projects/update_server/internal/http/auth_handlers.go`
- `/Users/delete/projects/update_server/internal/http/auth_middleware.go`
- `/Users/delete/projects/update_server/internal/http/auth_integration_test.go`
- `/Users/delete/projects/update_server/web/templates/layouts/base.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/home.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/admin.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/login.gohtml`
- `/Users/delete/projects/update_server/web/static/app.css`
## Database Changes
- no schema or migration changes were required in this stage;
- the existing `users` and `sessions` tables from Agent 02 are now actively used for bootstrap, login, session lookup, and logout invalidation;
- session tokens continue to be stored hashed only;
- user `last_login_at` and session `last_seen_at` are now updated by runtime auth flows.
## API Or Route Changes
- added `GET /admin/login` for the server-rendered login form;
- added `POST /admin/login` to authenticate an admin user and issue a session cookie;
- added `POST /admin/logout` to invalidate the current session and clear the cookie;
- changed `/admin` from a public placeholder to a protected route group guarded by session middleware and admin-role checks;
- retained the existing `/api/v1` route scaffold unchanged.
## Commands And Tests Run
- `gofmt -w ./cmd ./internal` - passed;
- `GOCACHE=/tmp/go-build-auth GOMODCACHE=/tmp/go-mod-auth go mod tidy` - initially failed in the sandbox due network/DNS restrictions, then passed after rerunning with approval;
- `GOCACHE=/tmp/go-build-auth GOMODCACHE=/tmp/go-mod-auth go test ./...` - passed;
- `GOCACHE=/tmp/go-build-auth GOMODCACHE=/tmp/go-mod-auth go build -o /tmp/update-server-auth ./cmd/server` - passed;
- `GOCACHE=/tmp/go-build-auth GOMODCACHE=/tmp/go-mod-auth go build -o /tmp/update-migrate-auth ./cmd/migrate` - passed.
## Known Limitations
- CSRF protection is not implemented yet for admin forms; this remains for the hardening stage;
- login rate limiting is not implemented yet;
- bootstrap is environment-driven only in this stage; there is no separate one-time bootstrap CLI yet;
- if no active admin exists and the configured `ADMIN_EMAIL` already belongs to a non-admin user, bootstrap currently logs a warning and leaves that conflict for an operator to resolve;
- there is no admin user-management UI yet beyond the initial bootstrap/login foundation.
## Recommended Next Step
Agent 04 should build project, tag, and release management on top of the now-protected `/admin` route group, reusing the authenticated session context instead of adding a parallel auth path.
## Notes For Validator
- verify that `POST /admin/login` creates a DB-backed session and stores only the token hash in SQLite, not the raw cookie value;
- verify that `/admin` redirects when unauthenticated and succeeds when the issued session cookie is replayed;
- verify that `POST /admin/logout` invalidates the existing session record so the old cookie no longer grants access;
- verify bootstrap behavior both when `ADMIN_EMAIL` and `ADMIN_PASSWORD` are present and when they are absent.

View file

@ -0,0 +1,105 @@
# Agent
Name: Agent 04 - Projects, Tags, And Releases
Stage: Projects, Tags, And Releases
Date: 2026-04-14
## Scope
Implemented the core product data management stage on top of the existing authenticated `/admin` route group.
Completed in this stage:
- added artifact storage configuration rooted under `DATA_DIR/artifacts`, with validation that artifacts stay outside the public static directory;
- implemented local filesystem artifact storage with temp-file staging and final path validation;
- added project repository methods for create, update, list, archive toggle, and project-tag assignment queries;
- added tag repository methods for create, update, list, delete-if-unused, and project usage queries;
- added release repository methods for create, lookup, and per-project release listing;
- implemented a release upload service that sanitizes filenames, streams uploads to a temp artifact, computes SHA-256 checksums, detects content type, moves the file into structured private storage, and writes release metadata to SQLite;
- extended the protected admin router with project list/create/detail/archive routes, tag list/create/detail/delete routes, project-tag attach or detach actions, and release upload handling;
- replaced the placeholder dashboard with project/tag/release-aware admin pages and added server-rendered templates for project list, project detail, project creation, tag list, and tag detail;
- added integration coverage for the admin flow that logs in, creates and edits project/tag data, attaches tags, uploads a release, verifies the checksum and sanitized filename, and checks the artifact on disk.
## Files Changed
- `/Users/delete/projects/update_server/internal/app/app.go`
- `/Users/delete/projects/update_server/internal/config/config.go`
- `/Users/delete/projects/update_server/internal/db/errors.go`
- `/Users/delete/projects/update_server/internal/db/models.go`
- `/Users/delete/projects/update_server/internal/db/projects.go`
- `/Users/delete/projects/update_server/internal/db/tags.go`
- `/Users/delete/projects/update_server/internal/db/releases.go`
- `/Users/delete/projects/update_server/internal/http/router.go`
- `/Users/delete/projects/update_server/internal/http/render.go`
- `/Users/delete/projects/update_server/internal/http/view_data.go`
- `/Users/delete/projects/update_server/internal/http/handlers.go`
- `/Users/delete/projects/update_server/internal/http/auth_handlers.go`
- `/Users/delete/projects/update_server/internal/http/admin_common.go`
- `/Users/delete/projects/update_server/internal/http/admin_projects.go`
- `/Users/delete/projects/update_server/internal/http/admin_tags.go`
- `/Users/delete/projects/update_server/internal/http/auth_integration_test.go`
- `/Users/delete/projects/update_server/internal/http/projects_integration_test.go`
- `/Users/delete/projects/update_server/internal/releases/service.go`
- `/Users/delete/projects/update_server/internal/slug/slug.go`
- `/Users/delete/projects/update_server/internal/storage/local.go`
- `/Users/delete/projects/update_server/web/templates/layouts/base.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/admin.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/home.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/login.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/projects.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/project_form.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/project_detail.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/tags.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/tag_form.gohtml`
- `/Users/delete/projects/update_server/web/static/app.css`
- `/Users/delete/projects/update_server/docs/agents/handoffs/04-projects-releases.md`
## Database Changes
- no schema or migration changes were required in this stage;
- the existing `projects`, `tags`, `project_tags`, and `releases` tables are now actively used by repository methods and protected admin workflows;
- release `storage_path` values are now persisted as relative paths underneath the configured artifact root;
- release rows now store sanitized filenames, SHA-256 checksum values, detected content type, file size, release notes, and uploader linkage.
## API Or Route Changes
- added `GET /admin/projects` for the protected project list page;
- added `GET /admin/projects/new` and `POST /admin/projects` for project creation;
- added `GET /admin/projects/{projectID}` and `POST /admin/projects/{projectID}` for project detail and editing;
- added `POST /admin/projects/{projectID}/archive` for archive or restore actions;
- added `POST /admin/projects/{projectID}/tags` and `POST /admin/projects/{projectID}/tags/{tagID}/detach` for project-tag assignment;
- added `POST /admin/projects/{projectID}/releases` for protected release uploads;
- added `GET /admin/tags`, `GET /admin/tags/new`, and `POST /admin/tags` for tag list and creation;
- added `GET /admin/tags/{tagID}`, `POST /admin/tags/{tagID}`, and `POST /admin/tags/{tagID}/delete` for tag edit and delete-if-unused behavior;
- updated `GET /admin` to show project/tag/release summary data instead of the auth-only placeholder;
- kept `/api/v1` unchanged and intentionally did not add API key or client update endpoints in this stage.
## Commands And Tests Run
- `gofmt -w ./internal ./cmd` - passed;
- `GOCACHE=/tmp/go-build-agent04 GOMODCACHE=/tmp/go-mod-agent04 go test ./...` - initially failed in the sandbox due dependency download DNS restrictions, then passed after rerunning with approval;
- `GOCACHE=/tmp/go-build-agent04 GOMODCACHE=/tmp/go-mod-agent04 go build -o /tmp/update-server-agent04 ./cmd/server` - passed;
- `GOCACHE=/tmp/go-build-agent04 GOMODCACHE=/tmp/go-mod-agent04 go build -o /tmp/update-migrate-agent04 ./cmd/migrate` - passed.
## Known Limitations
- CSRF protection is still not implemented for admin forms, including the new project, tag, archive, and upload actions;
- release deletion or disable flows are not implemented in this stage;
- there is still no client-facing download or metadata endpoint for releases; only the protected admin upload and metadata path is present;
- duplicate project slugs, tag slugs, and `(project_id, version, build)` release combinations are rejected rather than offering replace-in-place behavior;
- upload handling currently relies on the standard multipart temp-file path before final storage, which is acceptable for MVP but not yet a custom streaming parser.
## Recommended Next Step
Agent 05 should implement API key generation, hashing, permissions, and scope evaluation on top of the now-working project and tag data model, using the existing `projects`, `tags`, and assignment relationships for allow-list and deny-list management.
## Notes For Validator
- verify that all new admin project and tag routes remain inside the existing authenticated `/admin` route group and reuse the session context;
- verify that uploaded artifacts land under `DATA_DIR/artifacts` and not under `web/static`;
- verify that uploaded filenames are sanitized before persistence and that `releases.checksum_sha256` matches the actual file bytes on disk;
- verify that release metadata rows are written to SQLite with the expected storage path, size, content type, and uploader linkage;
- verify that project archive or restore toggles `projects.is_active`;
- verify that tag deletion is blocked while the tag is still attached to a project.

View file

@ -0,0 +1,63 @@
# Agent
Name: Agent 05 - API Keys And Access Control (fix round)
Stage: API Keys And Access Control
Date: 2026-04-14
## Scope
Fixed the validation findings for Agent 05 without expanding into the client API stage.
Completed in this fix round:
- added explicit anti-cache headers for the one-time raw API key reveal response so the secret-bearing HTML is marked non-cacheable;
- changed the immediate post-create detail render to hydrate from the persisted API key record and persisted scope rows while still showing the raw key only on that one response;
- extended HTTP integration coverage to verify:
- the creation response includes anti-cache headers;
- the creation response shows saved name, description, scope mode, permissions, and selected project or tag rules;
- the raw key is present on the creation response and absent on later detail loads.
## Files Changed
- `/Users/delete/projects/update_server/internal/http/admin_api_keys.go`
- `/Users/delete/projects/update_server/internal/http/api_keys_integration_test.go`
- `/Users/delete/projects/update_server/docs/agents/handoffs/05-api-keys-fix.md`
## Database Changes
- no schema or migration changes were required;
- the existing API key hash and scope storage model remains unchanged.
## API Or Route Changes
- no routes were added or removed;
- `POST /admin/api-keys` now returns the one-time reveal page with explicit anti-cache headers:
- `Cache-Control: no-store, private, max-age=0`
- `Pragma: no-cache`
- `Expires: 0`
## Commands And Tests Run
- `gofmt -w internal/http/admin_api_keys.go internal/http/api_keys_integration_test.go` - passed;
- `GOCACHE=/tmp/go-build-agent05-fix GOMODCACHE=/tmp/go-mod-agent05-2 go test ./internal/http` - passed;
- `GOCACHE=/tmp/go-build-agent05-fix-all GOMODCACHE=/tmp/go-mod-agent05-2 go test ./...` - passed;
- `GOCACHE=/tmp/go-build-agent05-fix-build GOMODCACHE=/tmp/go-mod-agent05-2 go build -o /tmp/update-server-agent05-fix ./cmd/server` - passed;
- `GOCACHE=/tmp/go-build-agent05-fix-build2 GOMODCACHE=/tmp/go-mod-agent05-2 go build -o /tmp/update-migrate-agent05-fix ./cmd/migrate` - passed.
## Known Limitations
- the one-time reveal still intentionally happens on the direct POST response rather than a redirect flow so the raw key never has to enter query strings or persistent storage;
- CSRF protection is still not implemented for admin API key forms;
- the client `/api/v1` endpoints still do not use the API key middleware yet; that remains for Agent 06.
## Recommended Next Step
Agent 06 should wire the existing API key middleware into the client `/api/v1` endpoints for accessible project listing, latest release lookup, and authenticated artifact download.
## Notes For Validator
- verify that the post-create response shows persisted saved values immediately, without requiring a manual refresh;
- verify that the raw key appears only on the secret-bearing creation response and not on later `GET /admin/api-keys/{id}` detail loads;
- verify the one-time reveal response includes the anti-cache headers listed above.

View file

@ -0,0 +1,90 @@
# Agent
Name: Agent 05 - API Keys And Access Control
Stage: API Keys And Access Control
Date: 2026-04-14
## Scope
Implemented the API key lifecycle and access-control stage on top of the existing authenticated admin workspace and the project or tag model from Agent 04.
Completed in this stage:
- added a dedicated `internal/apikeys` service for secure API key generation, SHA-256 hashing, lookup, lifecycle checks, and project scope evaluation;
- implemented full API key repository support for create, update, list, revoke or activate, last-used tracking, project and tag rule storage, and effective access queries;
- added minimal protected admin pages for API key list, creation, detail, update, and revoke or activate actions;
- implemented one-time raw key reveal behavior by showing the generated key only in the immediate creation response while persisting only the short prefix and hash;
- added permission and project-scope middleware helpers for future `/api/v1` client routes using bearer authentication;
- added integration and unit coverage for hashed storage, expired or revoked key rejection, all five scope modes, scope transitions, middleware enforcement, and admin key management flow.
## Files Changed
- `/Users/delete/projects/update_server/internal/app/app.go`
- `/Users/delete/projects/update_server/internal/db/models.go`
- `/Users/delete/projects/update_server/internal/db/apikeys.go`
- `/Users/delete/projects/update_server/internal/apikeys/context.go`
- `/Users/delete/projects/update_server/internal/apikeys/service.go`
- `/Users/delete/projects/update_server/internal/apikeys/service_test.go`
- `/Users/delete/projects/update_server/internal/http/router.go`
- `/Users/delete/projects/update_server/internal/http/handlers.go`
- `/Users/delete/projects/update_server/internal/http/view_data.go`
- `/Users/delete/projects/update_server/internal/http/admin_api_keys.go`
- `/Users/delete/projects/update_server/internal/http/api_key_middleware.go`
- `/Users/delete/projects/update_server/internal/http/api_key_middleware_test.go`
- `/Users/delete/projects/update_server/internal/http/api_keys_integration_test.go`
- `/Users/delete/projects/update_server/internal/http/auth_integration_test.go`
- `/Users/delete/projects/update_server/web/templates/layouts/base.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/api_keys.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/api_key_form.gohtml`
- `/Users/delete/projects/update_server/web/static/app.css`
- `/Users/delete/projects/update_server/docs/agents/handoffs/05-api-keys.md`
## Database Changes
- no new migrations were required because the existing `api_keys`, `api_key_project_access`, and `api_key_tag_access` tables already existed from Agent 02 and the scope guard triggers already existed from migration `0003_api_key_scope_guards.sql`;
- the new repository code now actively uses those tables and trigger rules for key lifecycle, project allow or deny lists, and tag allow or deny lists;
- API keys are stored with a short visible `key_prefix` and a hashed `key_hash`; the raw key is never persisted.
## API Or Route Changes
- added protected admin routes:
- `GET /admin/api-keys`
- `GET /admin/api-keys/new`
- `POST /admin/api-keys`
- `GET /admin/api-keys/{apiKeyID}`
- `POST /admin/api-keys/{apiKeyID}`
- `POST /admin/api-keys/{apiKeyID}/activate`
- added reusable middleware helpers for future client API routes:
- `requireAPIKey`
- `requireAPIKeyPermission`
- `requireAPIKeyProjectAccess`
- kept `/api/v1` client endpoints themselves out of scope for this stage so Agent 06 can wire them onto the new middleware and access-resolution layer.
## Commands And Tests Run
- `gofmt -w internal/app/app.go internal/db/models.go internal/db/apikeys.go internal/apikeys/context.go internal/apikeys/service.go internal/http/router.go internal/http/handlers.go internal/http/view_data.go internal/http/admin_api_keys.go internal/http/api_key_middleware.go internal/http/auth_integration_test.go internal/apikeys/service_test.go internal/http/api_key_middleware_test.go internal/http/api_keys_integration_test.go` - passed;
- `GOCACHE=/tmp/go-build-agent05-2 GOMODCACHE=/tmp/go-mod-agent05-2 go test ./...` - passed after downloading dependencies with approval;
- `GOCACHE=/tmp/go-build-agent05-build GOMODCACHE=/tmp/go-mod-agent05-2 go build -o /tmp/update-server-agent05 ./cmd/server` - passed;
- `GOCACHE=/tmp/go-build-agent05-build2 GOMODCACHE=/tmp/go-mod-agent05-2 go build -o /tmp/update-migrate-agent05 ./cmd/migrate` - passed.
## Known Limitations
- CSRF protection is still not implemented for admin forms, including the new API key creation, update, and revoke or activate actions;
- the admin API key UI is intentionally minimal and functional rather than polished;
- the one-time reveal happens on the direct POST response instead of a PRG redirect because the raw key must not be placed into query strings or persistent storage;
- no live client `/api/v1` endpoints use the new middleware yet; the groundwork is ready but the actual project list, latest-release, and download endpoints remain for Agent 06;
- expiration input currently accepts either empty, `YYYY-MM-DD`, or full RFC3339 UTC text rather than a more polished timezone-aware widget.
## Recommended Next Step
Agent 06 should wire the new `requireAPIKey`, `requireAPIKeyPermission`, and `requireAPIKeyProjectAccess` middleware into the client `/api/v1` endpoints for accessible-project listing, latest release lookup, and authenticated artifact download.
## Notes For Validator
- verify that only `key_prefix` and `key_hash` are stored in SQLite and that the raw key appears only in the immediate creation response;
- verify that revoked or expired keys are rejected by `requireAPIKey` with `401` and that missing permissions or blocked project scope return `403`;
- verify effective access resolution across all five scope modes, especially that archived projects do not appear in accessible-project results;
- verify scope transitions clear the incompatible access rows so the existing migration guards continue to succeed;
- verify the admin detail page preview matches the effective active project set for the key.

View file

@ -0,0 +1,100 @@
# Agent
Name: Agent 06 - Client API And Admin UI
Stage: Client API And Admin UI
Date: 2026-04-15
## Scope
Implemented the usable end-to-end product flow for admins and client applications on top of the existing project, release, and API key work from Agents 04 and 05.
Completed in this stage:
- added bearer-authenticated client endpoints under `/api/v1` for:
- listing accessible active projects;
- looking up the latest active release for an accessible project;
- fetching release metadata by release ID for an accessible project;
- downloading private release artifacts by release ID after auth, permission, and scope checks;
- reused the existing API key middleware and scope-evaluation service so disabled or expired keys return `401`, missing download permission returns `403`, and inaccessible projects or releases return `404` to avoid leaking unauthorized resources;
- added project slug lookup and latest-active-release repository queries so client handlers can resolve project-scoped metadata cleanly from persisted release rows;
- added a safe artifact-open path on top of the existing private local storage so downloads stream from the artifact root instead of exposing raw filesystem paths or static URLs;
- updated the API index and the home or dashboard copy so the live client API is discoverable instead of still looking like a placeholder;
- added small admin UI improvements on project detail and API key detail pages that show the client API paths and a bearer-auth quick-start example after an admin uploads a release or creates a key;
- added integration coverage for the client flow, including auth failures, scope enforcement, latest-release selection, release metadata lookup, and authorized or unauthorized download behavior.
## Files Changed
- `/Users/delete/projects/update_server/internal/db/projects.go`
- `/Users/delete/projects/update_server/internal/db/releases.go`
- `/Users/delete/projects/update_server/internal/storage/local.go`
- `/Users/delete/projects/update_server/internal/releases/service.go`
- `/Users/delete/projects/update_server/internal/http/router.go`
- `/Users/delete/projects/update_server/internal/http/handlers.go`
- `/Users/delete/projects/update_server/internal/http/admin_common.go`
- `/Users/delete/projects/update_server/internal/http/admin_projects.go`
- `/Users/delete/projects/update_server/internal/http/view_data.go`
- `/Users/delete/projects/update_server/internal/http/client_api.go`
- `/Users/delete/projects/update_server/internal/http/client_api_integration_test.go`
- `/Users/delete/projects/update_server/internal/http/api_keys_integration_test.go`
- `/Users/delete/projects/update_server/internal/http/projects_integration_test.go`
- `/Users/delete/projects/update_server/web/templates/pages/project_detail.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/api_key_form.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/api_keys.gohtml`
- `/Users/delete/projects/update_server/web/static/app.css`
- `/Users/delete/projects/update_server/docs/agents/handoffs/06-client-api-ui.md`
## Database Changes
- no new migrations or schema changes were required;
- added repository queries against the existing `projects` and `releases` tables:
- project lookup by slug;
- latest active release lookup ordered by persisted `created_at DESC, id DESC`;
- continued using the existing API key scope tables and scope modes without redesign.
## API Or Route Changes
- kept `GET /api/v1` public and upgraded it from a placeholder to a real client API index;
- added protected client routes behind bearer API key auth plus `can_download` permission:
- `GET /api/v1/projects`
- `GET /api/v1/projects/{projectSlug}/releases/latest`
- `GET /api/v1/releases/{releaseID}`
- `GET /api/v1/releases/{releaseID}/download`
- resource access behavior for client routes:
- missing, invalid, disabled, or expired API key -> `401`
- authenticated key without download permission -> `403`
- inaccessible or archived project or release -> `404`
- admin UI additions:
- project detail page now shows the relevant client API paths for that project and latest release;
- API key detail page now shows a bearer-auth quick-start example plus the accessible project metadata paths.
## Commands And Tests Run
- `gofmt -w internal/db/projects.go internal/db/releases.go internal/storage/local.go internal/http/view_data.go internal/http/admin_common.go internal/http/admin_projects.go internal/http/router.go internal/http/handlers.go internal/http/client_api.go internal/releases/service.go internal/http/api_keys_integration_test.go internal/http/projects_integration_test.go internal/http/client_api_integration_test.go` - passed
- `GOCACHE=/tmp/go-build-agent06-http GOMODCACHE=/tmp/go-mod-agent06-http go test ./internal/http ./internal/releases ./internal/db ./internal/apikeys` - initially failed in sandbox because module downloads could not resolve DNS, then passed after rerunning with approval
- `GOCACHE=/tmp/go-build-agent06-all GOMODCACHE=/tmp/go-mod-agent06-http go test ./...` - passed
- `GOCACHE=/tmp/go-build-agent06-build GOMODCACHE=/tmp/go-mod-agent06-http go build -o /tmp/update-server-agent06 ./cmd/server` - passed
- `GOCACHE=/tmp/go-build-agent06-migrate GOMODCACHE=/tmp/go-mod-agent06-http go build -o /tmp/update-migrate-agent06 ./cmd/migrate` - passed
## Known Limitations
- “Latest” currently means the newest active persisted release by `created_at` and `id`, not semantic-version comparison;
- the optional client query parameters mentioned in the product spec (`current_version`, `channel`, `platform`, `arch`) are still not implemented;
- the client API does not yet expose full per-project release listing; this stage focused on the required list, latest-metadata, metadata-by-ID, and download flow;
- the admin quick-start example can show the real raw key only on the one-time create response; later detail views intentionally fall back to a placeholder token;
- broader hardening work such as CSRF completion, rate limiting, security headers, audit logging polish, and deployment proxy setup remains out of scope for this stage.
## Recommended Next Step
Run the validation pass for Agent 06, then move to Agent 07 to implement the planned hardening and deployment-focused follow-up: CSRF, security headers, rate limiting, audit/logging polish, and deployment readiness around the now-working end-to-end product flow.
## Notes For Validator
- verify that client routes require `Authorization: Bearer <api_key>` and that disabled or expired keys are rejected with `401`;
- verify that client routes require `can_download` and return `403` when the key authenticates but lacks download permission;
- verify that unauthorized, archived, or out-of-scope projects and releases return `404` from metadata and download paths rather than leaking through a `403`;
- verify that `GET /api/v1/projects` returns only active projects allowed by the keys scope evaluation;
- verify that the latest-release endpoint selects the newest active persisted release row for the project;
- verify that the download endpoint streams bytes from private artifact storage and does not expose static URLs or raw filesystem paths;
- verify that the project detail and API key detail admin pages visibly expose the new client API quick-start information.

View file

@ -0,0 +1,134 @@
# Agent
Name: Agent 07 - Security And Deployment Hardening
Stage: Security And Deployment Hardening
Date: 2026-04-15
## Scope
Hardened the existing Go/chi/SQLite application for internet-facing deployment without changing the product model or admin/client flow.
Completed in this stage:
- added stricter HTTP server defaults:
- `ReadHeaderTimeout`
- `MaxHeaderBytes`
- higher default read/write/idle timeouts suitable for uploads and authenticated downloads
- added global security headers and route-specific cache controls:
- `Content-Security-Policy`
- `X-Frame-Options`
- `X-Content-Type-Options`
- `Referrer-Policy`
- `Permissions-Policy`
- `Cross-Origin-Opener-Policy`
- `Cross-Origin-Resource-Policy`
- `Strict-Transport-Security` when `APP_BASE_URL` is `https`
- `Cache-Control: no-store` on admin and protected client API responses
- `Vary: Cookie` or `Vary: Authorization` on the appropriate routes
- added trusted-proxy awareness so forwarded headers are only trusted when `TRUST_PROXY_HEADERS=true`;
- added in-memory rate limiting for:
- `POST /admin/login`
- protected client API routes under `/api/v1`
- added CSRF protection for all admin POST flows, including login, logout, project/tag/API key forms, tag attach or detach, archive or restore, and multipart release upload;
- rotated or cleared the admin CSRF cookie on login and logout, and scoped both session and CSRF cookies to `/admin`;
- tightened local data directory permissions for SQLite and data storage;
- added regression coverage for CSRF rejection, hardened cookie defaults, security headers, and both rate-limited route groups;
- added first-pass deployment assets:
- multi-stage `Dockerfile`
- hardened `docker-compose.yml`
- Caddy example
- Nginx example
- env example
- deployment, Proxmox, backup, and restore notes.
## Files Changed
- `/Users/delete/projects/update_server/internal/config/config.go`
- `/Users/delete/projects/update_server/internal/app/app.go`
- `/Users/delete/projects/update_server/internal/db/open.go`
- `/Users/delete/projects/update_server/internal/auth/service.go`
- `/Users/delete/projects/update_server/internal/http/router.go`
- `/Users/delete/projects/update_server/internal/http/security.go`
- `/Users/delete/projects/update_server/internal/http/rate_limit.go`
- `/Users/delete/projects/update_server/internal/http/csrf.go`
- `/Users/delete/projects/update_server/internal/http/auth_handlers.go`
- `/Users/delete/projects/update_server/internal/http/admin_common.go`
- `/Users/delete/projects/update_server/internal/http/admin_api_keys.go`
- `/Users/delete/projects/update_server/internal/http/view_data.go`
- `/Users/delete/projects/update_server/internal/http/auth_integration_test.go`
- `/Users/delete/projects/update_server/internal/http/projects_integration_test.go`
- `/Users/delete/projects/update_server/internal/http/api_keys_integration_test.go`
- `/Users/delete/projects/update_server/internal/http/security_integration_test.go`
- `/Users/delete/projects/update_server/web/templates/layouts/base.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/login.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/project_form.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/project_detail.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/tag_form.gohtml`
- `/Users/delete/projects/update_server/web/templates/pages/api_key_form.gohtml`
- `/Users/delete/projects/update_server/web/templates/partials/csrf_field.gohtml`
- `/Users/delete/projects/update_server/.dockerignore`
- `/Users/delete/projects/update_server/Dockerfile`
- `/Users/delete/projects/update_server/docker-compose.yml`
- `/Users/delete/projects/update_server/deploy/Caddyfile.example`
- `/Users/delete/projects/update_server/deploy/nginx.update-server.conf.example`
- `/Users/delete/projects/update_server/deploy/update-server.env.example`
- `/Users/delete/projects/update_server/docs/DEPLOYMENT.md`
- `/Users/delete/projects/update_server/docs/agents/handoffs/07-security-deploy.md`
## Database Changes
- no migrations or schema changes were required;
- SQLite remains the production database;
- deployment notes now explicitly call out WAL-mode backup and restore handling for:
- `db.sqlite`
- `db.sqlite-wal`
- `db.sqlite-shm`
- `artifacts/`.
## API Or Route Changes
- no new product endpoints were added;
- middleware behavior changed for existing routes:
- all `/admin` responses now emit hardened headers and `no-store` caching rules;
- all `/admin` POST routes now require a valid CSRF token;
- `POST /admin/login` is rate limited by client IP;
- protected `/api/v1` routes now emit hardened headers and `no-store` caching rules;
- protected `/api/v1` routes are rate limited by client IP before API-key auth;
- session cookies are now scoped to `/admin` and retain `HttpOnly`, `SameSite=Lax`, and conditional `Secure`;
- CSRF cookies are now scoped to `/admin` and use `HttpOnly`, `SameSite=Strict`, and conditional `Secure`.
## Commands And Tests Run
- `gofmt -w internal/config/config.go internal/app/app.go internal/db/open.go internal/auth/service.go internal/http/router.go internal/http/security.go internal/http/rate_limit.go internal/http/csrf.go internal/http/auth_handlers.go internal/http/view_data.go internal/http/admin_common.go internal/http/admin_api_keys.go internal/http/auth_integration_test.go internal/http/projects_integration_test.go internal/http/api_keys_integration_test.go internal/http/security_integration_test.go` - passed
- `go test ./internal/http` - passed
- `go test ./...` - passed
- `go build ./cmd/server` - passed
- `go build ./cmd/migrate` - passed
- `docker compose config` - could not run in this environment because `docker` is not installed
## Known Limitations
- rate limiting is in-memory and per-process, so counters reset on restart and are not shared across multiple app instances;
- Docker and reverse-proxy examples were added and reviewed statically, but they were not live-validated here because Docker is unavailable in this workspace;
- `Strict-Transport-Security` only appears when `APP_BASE_URL` is configured with `https`, which is the intended production setup behind TLS termination;
- the proxy still must be configured correctly to keep the app private and to strip or control forwarded headers before `TRUST_PROXY_HEADERS=true` is safe.
## Recommended Next Step
Run the Agent 07 validation pass, with special attention to:
- CSRF enforcement on every admin POST flow, including multipart upload;
- security headers and private-cache headers on admin and protected client API responses;
- login and client API rate limiting behavior;
- cookie flags and `/admin` cookie scoping;
- deployment docs and example proxy/container files on a host that has Docker and a reverse proxy available.
## Notes For Validator
- verify that a missing or invalid admin CSRF token returns `403` and that the normal admin flows still succeed when the token is present;
- verify that session cookies are only scoped to `/admin` and that secure-cookie behavior follows the configured `APP_BASE_URL` scheme;
- verify that `TRUST_PROXY_HEADERS=false` leaves client IP handling on the socket remote address;
- verify that protected `/api/v1` responses include `Cache-Control: no-store`, `Vary: Authorization`, and the shared security headers;
- if possible, validate `docker compose up --build` plus one reverse-proxy example on a real machine, since that could not be executed in this environment.

View file

@ -0,0 +1,13 @@
# Handoffs Directory
Save one handoff markdown file here after every implementation stage.
Naming convention:
- `01-foundation.md`
- `02-database.md`
- `03-auth.md`
- `04-projects-releases.md`
- `05-api-keys.md`
- `06-client-api-ui.md`
- `07-security-deploy.md`

View file

@ -0,0 +1,45 @@
# Validation Report Template
## Validator
Name: Codex Validation Agent
Stage Reviewed: Agent 01 - Foundation
Date: 2026-04-13
## Reviewed Inputs
- `/Users/delete/projects/update_server/docs/agents/WORKFLOW.md`
- `/Users/delete/projects/update_server/PRODUCT_SPEC.md`
- `/Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md`
- `/Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md`
- `/Users/delete/projects/update_server/docs/agents/OPERATOR_QUICKSTART_RU.md`
- `/Users/delete/projects/update_server/docs/agents/handoffs/01-foundation.md`
- implementation files under `cmd/server`, `internal/app`, `internal/config`, `internal/http`, `web/templates`, `web/static`, and `migrations`
- `go test ./...` -> passed
- `go build -o /tmp/update-server ./cmd/server` -> passed
- live smoke checks against `127.0.0.1:18080`:
- `GET /healthz` -> `200 OK`
- `GET /` -> `200 OK`
- `GET /admin` -> `200 OK`
- `GET /api/v1` -> `200 OK`
## Findings
No blocking findings.
The stage stays within the agreed scope, the server boots successfully, the route scaffolding is present, and the template/static foundation is ready for Agent 02.
## Required Fixes
None.
## Optional Improvements
- Add a small smoke-test suite for the foundation routes in a later stage once the HTTP surface becomes more stable.
- Initialize a git repository if you want future validators to compare diffs with `git status` and `git diff`.
## Status
`APPROVED`

View file

@ -0,0 +1,54 @@
# Validation Report Template
## Validator
Name: Codex Validation Agent
Stage Reviewed: Agent 02 - Database And Migrations
Date: 2026-04-14
## Reviewed Inputs
- `/Users/delete/projects/update_server/docs/agents/WORKFLOW.md`
- `/Users/delete/projects/update_server/PRODUCT_SPEC.md`
- `/Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md`
- `/Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md`
- `/Users/delete/projects/update_server/docs/agents/OPERATOR_QUICKSTART_RU.md`
- `/Users/delete/projects/update_server/docs/agents/handoffs/02-database.md`
- previous validation report: `/Users/delete/projects/update_server/docs/agents/validation/01-foundation-validation.md`
- implementation files under `cmd/migrate`, `internal/db`, `internal/config`, `internal/app`, `internal/http`, and `migrations`
- `.gitignore` and `Justfile`
- `GOCACHE=/tmp/go-build-agent02 GOMODCACHE=/tmp/go-mod-agent02 go test ./...` -> passed
- `GOCACHE=/tmp/go-build-agent02 GOMODCACHE=/tmp/go-mod-agent02 go build -o /tmp/update-server-agent02-bin ./cmd/server` -> passed
- `GOCACHE=/tmp/go-build-agent02 GOMODCACHE=/tmp/go-mod-agent02 go build -o /tmp/update-migrate-agent02-bin ./cmd/migrate` -> passed
- `DATA_DIR=/tmp/update-server-agent02 APP_BASE_URL=http://127.0.0.1:18080 /tmp/update-migrate` -> passed
- live smoke checks against `127.0.0.1:18081` after starting `/tmp/update-server-agent02-bin` with a fresh `DATA_DIR`:
- `GET /healthz` -> `200 OK` with `"database":"ok"`
- `GET /` -> `200 OK`
- `GET /api/v1` -> `200 OK`
## Findings
No blocking findings.
The stage satisfies the agreed scope:
- the SQLite schema covers the required tables;
- migrations are present and executable;
- migration checksum tracking is implemented and tested;
- the server startup path opens SQLite and auto-applies migrations;
- the health endpoint now reflects database readiness.
## Required Fixes
None.
## Optional Improvements
- Add explicit tests for `scope_mode` transition guard behavior, not just incompatible access-row insertion.
- Update the small home-page eyebrow copy from `Foundation Stage` to something database-specific for consistency.
## Status
`APPROVED`

View file

@ -0,0 +1,57 @@
# Validation Report Template
## Validator
Name: Codex Validation Agent
Stage Reviewed: Agent 03 - Authentication And Admin Sessions
Date: 2026-04-14
## Reviewed Inputs
- `/Users/delete/projects/update_server/docs/agents/WORKFLOW.md`
- `/Users/delete/projects/update_server/PRODUCT_SPEC.md`
- `/Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md`
- `/Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md`
- `/Users/delete/projects/update_server/docs/agents/OPERATOR_QUICKSTART_RU.md`
- `/Users/delete/projects/update_server/docs/agents/handoffs/03-auth.md`
- previous validation report: `/Users/delete/projects/update_server/docs/agents/validation/02-database-validation.md`
- implementation files under `internal/auth`, `internal/db`, `internal/http`, `internal/app`, `internal/config`, and `web/templates`
- `GOCACHE=/tmp/go-build-auth-validate GOMODCACHE=/tmp/go-mod-auth-validate go test ./...` -> passed
- `GOCACHE=/tmp/go-build-auth-validate GOMODCACHE=/tmp/go-mod-auth-validate go build -o /tmp/update-server-auth-validate ./cmd/server` -> passed
- `GOCACHE=/tmp/go-build-auth-validate GOMODCACHE=/tmp/go-mod-auth-validate go build -o /tmp/update-migrate-auth-validate ./cmd/migrate` -> passed
- live smoke checks against `127.0.0.1:18082` after starting `/tmp/update-server-auth-validate` with fresh bootstrap credentials and a fresh `DATA_DIR`:
- `GET /admin` -> `303 See Other` to `/admin/login`
- `GET /admin/login` -> `200 OK`
- `POST /admin/login` -> `303 See Other` with session cookie
- `GET /admin` with valid cookie -> `200 OK`
- SQLite inspection confirmed `sessions.token_hash` stores the SHA-256 of the cookie token, not the raw token
- `POST /admin/logout` -> `303 See Other`
- `GET /admin` with the old cookie after logout -> `303 See Other` to `/admin/login`
- SQLite inspection confirmed the session row was invalidated
## Findings
No blocking findings.
The stage satisfies the agreed scope:
- bootstrap admin creation is wired from environment configuration;
- passwords are hashed with bcrypt;
- session tokens are generated securely and stored hashed in SQLite;
- the `/admin` route group is protected by session middleware and role checks;
- login and logout behavior works in live validation, including old-cookie rejection after logout.
## Required Fixes
None.
## Optional Improvements
- Decide explicitly in a later stage whether the login endpoint should stay generic for any active user session or reject non-admin roles up front for the current admin-only UI.
- Add CSRF protection when the security-hardening stage begins, especially for `POST /admin/logout` and future admin forms.
## Status
`APPROVED`

View file

@ -0,0 +1,62 @@
# Validation Report Template
## Validator
Name: Codex Validation Agent
Stage Reviewed: Agent 04 - Projects, Tags, And Releases
Date: 2026-04-14
## Reviewed Inputs
- `/Users/delete/projects/update_server/docs/agents/WORKFLOW.md`
- `/Users/delete/projects/update_server/PRODUCT_SPEC.md`
- `/Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md`
- `/Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md`
- `/Users/delete/projects/update_server/docs/agents/OPERATOR_QUICKSTART_RU.md`
- `/Users/delete/projects/update_server/docs/agents/handoffs/04-projects-releases.md`
- previous validation report: `/Users/delete/projects/update_server/docs/agents/validation/03-auth-validation.md`
- implementation files under `internal/db`, `internal/http`, `internal/releases`, `internal/storage`, `internal/slug`, `internal/app`, `internal/config`, and `web/templates`
- `GOCACHE=/tmp/go-build-agent04-validate GOMODCACHE=/tmp/go-mod-agent04-validate go test ./...` -> passed
- `GOCACHE=/tmp/go-build-agent04-validate GOMODCACHE=/tmp/go-mod-agent04-validate go build -o /tmp/update-server-agent04-validate ./cmd/server` -> passed
- `GOCACHE=/tmp/go-build-agent04-validate GOMODCACHE=/tmp/go-mod-agent04-validate go build -o /tmp/update-migrate-agent04-validate ./cmd/migrate` -> passed
- live smoke checks against `127.0.0.1:18083` after starting `/tmp/update-server-agent04-validate` with fresh bootstrap credentials and a fresh `DATA_DIR`:
- `GET /admin/projects` without session -> `303 See Other` to `/admin/login?next=%2Fadmin%2Fprojects`
- `POST /admin/login` -> `303 See Other` with session cookie
- `GET /admin/projects` with session -> `200 OK`
- `POST /admin/projects` -> project created
- `POST /admin/tags` -> tag created
- `POST /admin/projects/1/tags` -> tag attached
- `POST /admin/projects/1/releases` with multipart file upload -> `303 See Other`
- SQLite inspection confirmed project, tag, project-tag link, and release metadata rows
- filesystem inspection confirmed artifact saved under `DATA_DIR/artifacts/...`, outside `web/static`
- checksum of stored artifact matched `releases.checksum_sha256`
- `POST /admin/tags/1/delete` while tag was still attached -> redirected with `tag-in-use`
- `POST /admin/projects/1/archive` -> project became archived in SQLite and UI
## Findings
No blocking findings.
The stage satisfies the agreed scope:
- protected admin CRUD flows exist for projects and tags;
- project-tag assignment works;
- release uploads are stored under the private artifact directory;
- release metadata is persisted with sanitized filename, checksum, size, content type, storage path, and uploader linkage;
- archive and tag-in-use protection behaviors work in live validation.
## Required Fixes
None.
## Optional Improvements
- Add an explicit unit or integration test for rejecting uploads that exceed `MAX_UPLOAD_BYTES`.
- Consider surfacing a success flash on the projects list page for newly created items instead of only redirecting to detail pages.
- Add release disable/delete flows in a later stage when the product needs release lifecycle management beyond upload.
## Status
`APPROVED`

View file

@ -0,0 +1,64 @@
# Validation Report Template
## Validator
Name: Codex Validation Agent
Stage Reviewed: Agent 05 - API Keys And Access Control
Date: 2026-04-14
## Reviewed Inputs
- `/Users/delete/projects/update_server/docs/agents/WORKFLOW.md`
- `/Users/delete/projects/update_server/PRODUCT_SPEC.md`
- `/Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md`
- `/Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md`
- `/Users/delete/projects/update_server/docs/agents/OPERATOR_QUICKSTART_RU.md`
- `/Users/delete/projects/update_server/docs/agents/handoffs/05-api-keys.md`
- `/Users/delete/projects/update_server/docs/agents/handoffs/05-api-keys-fix.md`
- previous stage validation report: `/Users/delete/projects/update_server/docs/agents/validation/04-projects-releases-validation.md`
- implementation files under `internal/apikeys`, `internal/db`, `internal/http`, `internal/app`, and `web/templates`
- `GOCACHE=/tmp/go-build-agent05-revalidate GOMODCACHE=/tmp/go-mod-agent05-revalidate go test ./...` -> passed
- `GOCACHE=/tmp/go-build-agent05-rebuild GOMODCACHE=/tmp/go-mod-agent05-rebuild go build -o /tmp/update-server-agent05-revalidate ./cmd/server` -> passed
- `GOCACHE=/tmp/go-build-agent05-remigrate GOMODCACHE=/tmp/go-mod-agent05-remigrate go build -o /tmp/update-migrate-agent05-revalidate ./cmd/migrate` -> passed
- live smoke checks against `127.0.0.1:18085` after starting `/tmp/update-server-agent05-revalidate` with a fresh `DATA_DIR`:
- `GET /healthz` -> `200 OK`
- `GET /admin/api-keys` without session -> `303 See Other` to `/admin/login?next=%2Fadmin%2Fapi-keys`
- `POST /admin/login` -> `303 See Other` with session cookie
- `POST /admin/projects` -> project created
- `POST /admin/tags` -> tag created
- `POST /admin/projects/1/tags` -> tag attached
- `POST /admin/api-keys` -> `200 OK` with `Cache-Control: no-store, private, max-age=0`, `Pragma: no-cache`, and `Expires: 0`
- the create response showed the raw key once and also showed the persisted saved values immediately: name, description, selected scope mode, permissions, selected tag rule, and effective access preview
- `GET /admin/api-keys/1` after creation -> `200 OK`, raw key no longer present in HTML
- SQLite inspection confirmed only `key_hash` was stored and confirmed the persisted tag scope row in `api_key_tag_access`
## Findings
No blocking findings.
The previously reported issues are fixed:
- the secret-bearing creation response is explicitly marked non-cacheable;
- the immediate post-create detail page is hydrated from persisted data while still showing the raw key only on that one response.
The stage now satisfies the agreed scope:
- API keys are generated securely and stored hashed;
- admin UI supports create, update, and revoke flows;
- allow-list and deny-list groundwork is in place for both projects and tags;
- middleware and scope evaluation are covered by tests and the create-flow regressions are fixed.
## Required Fixes
None.
## Optional Improvements
- Consider a future POST-Redirect-GET plus short-lived flash-secret design if you want to avoid browser refresh resubmitting the create form while still keeping the raw key out of persistent storage.
- Later client API validation should explicitly exercise disabled and expired keys through the public `/api/v1` endpoints once Agent 06 wires them in.
## Status
`APPROVED`

View file

@ -0,0 +1,77 @@
# Validation Report Template
## Validator
Name: Codex Validation Agent
Stage Reviewed: Agent 06 - Client API And Admin UI
Date: 2026-04-15
## Reviewed Inputs
- `/Users/delete/projects/update_server/docs/agents/WORKFLOW.md`
- `/Users/delete/projects/update_server/PRODUCT_SPEC.md`
- `/Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md`
- `/Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md`
- `/Users/delete/projects/update_server/docs/agents/OPERATOR_QUICKSTART_RU.md`
- `/Users/delete/projects/update_server/docs/agents/handoffs/06-client-api-ui.md`
- previous stage validation report: `/Users/delete/projects/update_server/docs/agents/validation/05-api-keys-validation.md`
- implementation files under `internal/http`, `internal/db`, `internal/releases`, `internal/storage`, `web/templates`, and `web/static`
- `GOCACHE=/tmp/go-build-agent06-validate GOMODCACHE=/tmp/go-mod-agent06-http go test ./...` -> passed
- `GOCACHE=/tmp/go-build-agent06-build-validate GOMODCACHE=/tmp/go-mod-agent06-http go build -o /tmp/update-server-agent06-validate ./cmd/server` -> passed
- `GOCACHE=/tmp/go-build-agent06-migrate-validate GOMODCACHE=/tmp/go-mod-agent06-http go build -o /tmp/update-migrate-agent06-validate ./cmd/migrate` -> passed
- live smoke checks against `127.0.0.1:18086` after starting `/tmp/update-server-agent06-validate` with a fresh `DATA_DIR`:
- `GET /healthz` -> `200 OK`
- `GET /api/v1` -> `200 OK` with public JSON index documenting bearer auth and the client routes
- `GET /api/v1/projects` without bearer token -> `401 Unauthorized` with `WWW-Authenticate: Bearer`
- admin login succeeded and a fresh test dataset was created:
- active projects: `desktop-app`, `mobile-app`
- archived project: `legacy-app`
- releases created for desktop, mobile, and legacy projects
- tag-scoped API key with `can_download`
- API key without `can_download`
- expired API key
- `GET /api/v1/projects` with the allowed tag-scoped key -> `200 OK`, returning only active authorized project `desktop-app`
- `GET /api/v1/projects` with key lacking `can_download` -> `403 Forbidden`
- `GET /api/v1/projects` with expired key -> `401 Unauthorized`
- `GET /api/v1/projects/desktop-app/releases/latest` with allowed key -> `200 OK`, returning latest active desktop release `1.1.0 / build-2`
- `GET /api/v1/projects/mobile-app/releases/latest` with allowed key -> `404 Not Found`
- `GET /api/v1/releases/3` for out-of-scope mobile release -> `404 Not Found`
- `GET /api/v1/releases/4` for archived-project release -> `404 Not Found`
- `GET /api/v1/releases/2` with allowed key -> `200 OK`, returning authorized release metadata
- `GET /api/v1/releases/2/download` with allowed key -> `200 OK`, streamed `desktop-release-1.1.0` with `Content-Disposition: attachment; filename=desktop-app-1.1.0.zip`
- `GET /admin/projects/1` with admin session -> `200 OK`, page showed `/api/v1/projects/desktop-app/releases/latest`, `/api/v1/releases/2`, and `/api/v1/releases/2/download`
- `GET /admin/api-keys/1` with admin session -> `200 OK`, page showed bearer-auth quick-start guidance and accessible client API paths
- SQLite inspection of `/tmp/update-server-agent06-live/db.sqlite` confirmed:
- latest desktop release persisted as release ID `2`
- mobile release persisted as release ID `3`
- archived-project release persisted as release ID `4`
- validation API keys persisted with the expected permission and expiry states
## Findings
No blocking findings.
The stage satisfies the agreed scope:
- the public `/api/v1` index is usable and documents the client routes;
- bearer-authenticated client endpoints enforce API key authentication and `can_download`;
- client project listing returns only active authorized projects;
- latest-release lookup, metadata lookup, and artifact download work for authorized resources;
- out-of-scope and archived resources are hidden behind `404`;
- downloads stream from private artifact storage instead of exposing static URLs;
- admin pages expose the new client API paths and quick-start guidance.
## Required Fixes
None.
## Optional Improvements
- If the product later needs richer updater logic, add support for semantic-version comparison or explicit release channels instead of using newest persisted `created_at` as the definition of “latest”.
- Agent 07 should harden the now-working client API with security headers, rate limiting, CSRF coverage for admin POST forms, and deployment-ready reverse proxy guidance.
## Status
`APPROVED`

View file

@ -0,0 +1,88 @@
# Validation Report Template
## Validator
Name: Codex Validation Agent
Stage Reviewed: Agent 07 - Security And Deployment Hardening
Date: 2026-04-15
## Reviewed Inputs
- `/Users/delete/projects/update_server/docs/agents/WORKFLOW.md`
- `/Users/delete/projects/update_server/PRODUCT_SPEC.md`
- `/Users/delete/projects/update_server/IMPLEMENTATION_PLAN.md`
- `/Users/delete/projects/update_server/DEVELOPMENT_WORKFLOW.md`
- `/Users/delete/projects/update_server/docs/agents/OPERATOR_QUICKSTART_RU.md`
- `/Users/delete/projects/update_server/docs/agents/handoffs/07-security-deploy.md`
- previous stage validation report: `/Users/delete/projects/update_server/docs/agents/validation/06-client-api-ui-validation.md`
- implementation files under `internal/config`, `internal/app`, `internal/db`, `internal/auth`, `internal/http`, `web/templates`, `deploy`, and root deployment files
- `GOCACHE=/tmp/go-build-agent07-validate GOMODCACHE=/tmp/go-mod-agent06-http go test ./...` -> passed
- `GOCACHE=/tmp/go-build-agent07-build GOMODCACHE=/tmp/go-mod-agent06-http go build -o /tmp/update-server-agent07-validate ./cmd/server` -> passed
- `GOCACHE=/tmp/go-build-agent07-migrate GOMODCACHE=/tmp/go-mod-agent06-http go build -o /tmp/update-migrate-agent07-validate ./cmd/migrate` -> passed
- `command -v docker` -> command not available in this environment, so `docker compose config` and container runtime checks could not be executed here
- live smoke checks against an HTTP-configured hardened server on `127.0.0.1:18088`:
- `GET /admin/login` -> `200 OK` with:
- `Cache-Control: no-store, private, max-age=0`
- `Content-Security-Policy`
- `X-Frame-Options: DENY`
- `X-Content-Type-Options: nosniff`
- `Referrer-Policy: no-referrer`
- `Permissions-Policy`
- `Cross-Origin-Opener-Policy: same-origin`
- `Cross-Origin-Resource-Policy: same-origin`
- `Vary: Cookie`
- CSRF cookie scoped to `/admin`, `HttpOnly`, `SameSite=Strict`
- `POST /admin/login` without CSRF token -> `403 Forbidden`
- `POST /admin/login` with valid CSRF token -> `303 See Other` with:
- session cookie scoped to `/admin`
- `HttpOnly`
- `SameSite=Lax`
- rotated CSRF cookie scoped to `/admin`
- `GET /api/v1/projects` without bearer token -> `401 Unauthorized` with:
- `Cache-Control: no-store, private, max-age=0`
- `Vary: Authorization`
- shared security headers
- created a download-capable API key through the hardened admin flow and verified:
- first two `GET /api/v1/projects` requests -> `200 OK`
- third request -> `429 Too Many Requests` with `Retry-After: 1`
- changing `X-Forwarded-For` between those requests did not bypass the rate limit while `TRUST_PROXY_HEADERS` remained false, confirming socket-address behavior in practice
- live smoke checks against an HTTPS-configured hardened server on `127.0.0.1:18089` with `APP_BASE_URL=https://updates.example.com`:
- `GET /admin/login` -> `200 OK` with `Strict-Transport-Security: max-age=31536000`
- CSRF cookie carried `Secure`, `Path=/admin`, `HttpOnly`, `SameSite=Strict`
- `POST /admin/login` with valid CSRF token -> `303 See Other` with session cookie carrying `Secure`, `Path=/admin`, `HttpOnly`, `SameSite=Lax`
- static review of deployment artifacts:
- `Dockerfile`
- `docker-compose.yml`
- `deploy/Caddyfile.example`
- `deploy/nginx.update-server.conf.example`
- `deploy/update-server.env.example`
- `docs/DEPLOYMENT.md`
## Findings
No blocking findings.
The stage satisfies the agreed scope:
- admin and protected client routes emit sane security defaults;
- CSRF protection is enforced on admin POST flows;
- cookies are scoped to `/admin` and switch to `Secure` when the public base URL is HTTPS;
- login and protected client API rate limits work;
- trusted proxy handling is opt-in;
- deployment and backup or restore documentation is present and coherent with the current architecture;
- artifacts remain private and continue flowing through authenticated application endpoints.
## Required Fixes
None.
## Optional Improvements
- Run `docker compose up --build` and one reverse-proxy example on the real target host before first production exposure, since Docker was unavailable in this validation environment.
- If you later run multiple app instances, replace the current in-memory rate limiter with a shared store-backed or proxy-backed limiter.
## Status
`APPROVED`

View file

@ -0,0 +1,13 @@
# Validation Directory
Save one validation markdown file here after every validation pass.
Naming convention:
- `01-foundation-validation.md`
- `02-database-validation.md`
- `03-auth-validation.md`
- `04-projects-releases-validation.md`
- `05-api-keys-validation.md`
- `06-client-api-ui-validation.md`
- `07-security-deploy-validation.md`