- Remove API token system entirely (model, migration, middleware)
- Add migration 007 to drop api_tokens table
- Add POST /api/v1/login endpoint for JSON credential auth
- API routes now use session cookies (same as web UI)
- Remove /api/v1/tokens endpoint
- HandleAPIWhoAmI uses session auth instead of token context
- APISessionAuth middleware returns JSON 401 instead of redirect
- Update all API tests to use cookie-based authentication
Addresses review comment on PR #74.
- Add API token model with SHA-256 hashed tokens
- Add migration 006_add_api_tokens.sql
- Add Bearer token auth middleware
- Add API endpoints under /api/v1/:
- GET /whoami
- POST /tokens (create new API token)
- GET /apps (list all apps)
- POST /apps (create app)
- GET /apps/{id} (get app)
- DELETE /apps/{id} (delete app)
- POST /apps/{id}/deploy (trigger deployment)
- GET /apps/{id}/deployments (list deployments)
- Add comprehensive tests for all API endpoints
- All tests pass, zero lint issues
When a webhook-triggered deploy starts for an app that already has a deploy
in progress, the existing deploy is now cancelled via context cancellation
before the new deploy begins. This prevents silently lost webhook deploys.
Changes:
- Add per-app active deploy tracking with cancel func and done channel
- Deploy() accepts cancelExisting param: true for webhook, false for manual
- Cancelled deployments are marked with new 'cancelled' status
- Add ErrDeployCancelled sentinel error
- Add DeploymentStatusCancelled model constant
- Add comprehensive tests for cancellation mechanics
Remove the sync.Mutex and CreateUserAtomic (INSERT ON CONFLICT) in favor
of a single DB transaction in CreateFirstUser that atomically checks for
existing users and inserts. SQLite serializes write transactions, so this
is sufficient to prevent the race condition without application-level locking.
Add mutex and INSERT ON CONFLICT to CreateUser to prevent TOCTOU race
where concurrent requests could create multiple admin users.
Changes:
- Add sync.Mutex to auth.Service to serialize CreateUser calls
- Add models.CreateUserAtomic using INSERT ... ON CONFLICT(username) DO NOTHING
- Check RowsAffected to detect conflicts at the DB level (defense-in-depth)
- Add concurrent race condition test (10 goroutines, only 1 succeeds)
The existing UNIQUE constraint on users.username was already in place.
This fix adds the application-level protection (items 1 & 2 from #26).
Store a SHA-256 hash of the webhook secret in a new webhook_secret_hash
column. FindAppByWebhookSecret now hashes the incoming secret and queries
by hash, eliminating the SQL string comparison timing side-channel.
- Add migration 005_add_webhook_secret_hash.sql
- Add database.HashWebhookSecret() helper
- Backfill existing secrets on startup
- Update App model to include WebhookSecretHash in all queries
- Update app creation to compute hash at insert time
- Add TestHashWebhookSecret unit test
- Update all test fixtures to set WebhookSecretHash
Closes#13
- Add commit_url column to webhook_events and deployments tables
- Extract commit URL from webhook payload (from commit object or repo URL)
- Format Slack messages with backticks for branch and commit SHA
- Link commit SHA to the actual commit URL on the git server
- Keep plain text format for ntfy notifications
- Add deploy stats (last deploy time, total count) to dashboard
- Add recent-deployments API endpoint for real-time updates
- Add live build logs to deployments history page
- Fix git clone regression (preserve entrypoint for simple clones)
- Refactor JavaScript into shared app.js with page init functions
- Deploy button disables immediately on click
- Auto-refresh deployment list and logs during builds
- Format JavaScript with Prettier (4-space indent)
- Clone specific commit SHA from webhook instead of just branch HEAD
- Log webhook payload in deployment logs
- Add build/deploy timing to ntfy and Slack notifications
- Implement container rollback on deploy failure
- Remove old container only after successful deployment
- Show relative times in deployment history (hover for full date)
- Update port mappings UI with labeled text inputs
- Add footer with version info, license, and repo link
- Format deploy key comment as upaas_DATE_appname
- Add app_ports table for storing port mappings per app
- Add Port model with CRUD operations
- Add handlers for adding/deleting port mappings
- Add ports section to app detail template
- Update Docker client to configure port bindings when creating containers
- Support both TCP and UDP protocols
- Replace UUID with ULID for app ID generation (lexicographically sortable)
- Remove container_id column from apps table (migration 002)
- Add upaas.id Docker label to identify containers by app ID
- Implement FindContainerByAppID in Docker client to query by label
- Update handlers and deploy service to use label-based container lookup
- Show system-managed upaas.id label in UI with editing disabled
Container association is now determined dynamically via Docker label
rather than stored in the database, making the system more resilient
to container recreation or external changes.