Commit Graph

9 Commits

Author SHA1 Message Date
7a34fc999c Update golangci-lint to v2.12.2 with canonical config (#187)
All checks were successful
Check / check (push) Successful in 4s
Bumps golangci-lint from v2.10.1 to v2.12.2 everywhere it is pinned and installs the canonical `.golangci.yml`, then fixes every finding the new linter surfaces so `make check` is green.

## Version pins

- `Dockerfile` lint stage: `golangci/golangci-lint:v2.12.2` (Debian-based), tag plus digest pin
- `script/bootstrap`: `GOLANGCI_LINT_VERSION=2.12.2` with updated `linux-amd64`/`linux-arm64` release-archive sha256 pins

## Config

`.golangci.yml` replaced with the canonical config. Material change: the old file declared `version: "2"` but kept settings under the legacy top-level `linters-settings` key, which golangci-lint v2 ignores — so the intended thresholds (`lll` 88, `funlen` 80/50, `cyclop` 15, `dupl` 100) were not being applied. The canonical file moves them under `linters.settings` and drops `issues.exclude-use-default`.

## Lint fixes (216 findings)

- `lll` (96): wrapped lines to the 88-column limit
- `noctx` (46): `httptest.NewRequestWithContext` with `t.Context()` throughout the tests
- `goconst` (24): shared constants for template/JSON keys in `internal/handlers` and repeated test literals
- `gosec` (23): app-page redirects now go through a `redirectToApp` helper that path-escapes the app ID (G710 open redirect); `http.ServeFile` of the internally derived deployment log path annotated like the adjacent `os.Stat` (G703)
- `dupl` (22): extracted a generic `findAllByAppID` in `internal/models`, a `deleteAppResource` helper in `internal/handlers`, a shared `parsePush` in `internal/service/webhook`, and table-driven/helper-based dedup in tests
- `nolintlint` (5): removed `//nolint:funlen` directives made obsolete by the new limits (plus one more that became obsolete after refactoring)
- `nilerr` (3, surfaced during fixing): resource-delete lookups now propagate the find error to the caller

No behavior changes intended; all tests pass and `make check` is green.

Note: golangci-lint v2.12 warns that `gomodguard` is deprecated in favor of `gomodguard_v2` — a future canonical-config update should address this centrally.
Co-authored-by: sneak <sneak@sneak.berlin>
Reviewed-on: #187
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-08-07 22:21:42 +02:00
57ec4331ef feat: add GitHub and GitLab webhook support (#170)
All checks were successful
Check / check (push) Successful in 3m17s
## Summary

Adds GitHub and GitLab push webhook support alongside the existing Gitea support.

closes #68

## What Changed

### Auto-detection of webhook source

The webhook handler now auto-detects which platform sent the webhook by examining HTTP headers:
- **Gitea**: `X-Gitea-Event`
- **GitHub**: `X-GitHub-Event`
- **GitLab**: `X-Gitlab-Event`

Existing Gitea webhooks continue to work unchanged. Unknown sources fall back to Gitea format for backward compatibility.

### Normalized push event

All three payload formats are parsed into a unified `PushEvent` struct containing:
- Source platform, ref, branch, commit SHA
- Repository name, clone URL, HTML URL
- Commit URL (with per-platform fallback logic)
- Pusher username/name

### New files

- **`internal/service/webhook/payloads.go`**: Source-specific payload structs (`GiteaPushPayload`, `GitHubPushPayload`, `GitLabPushPayload`), `ParsePushPayload()` dispatcher, per-platform parsers, branch extraction, and commit URL extraction functions.

### Modified files

- **`internal/service/webhook/types.go`**: Added `Source` type (gitea/github/gitlab/unknown), `DetectWebhookSource()`, `DetectEventType()`, and `PushEvent` normalized type. Moved `GiteaPushPayload` to payloads.go.
- **`internal/service/webhook/webhook.go`**: `HandleWebhook` now accepts a `Source` parameter and uses `ParsePushPayload()` for unified parsing instead of directly unmarshaling Gitea payloads.
- **`internal/handlers/webhook.go`**: Calls `DetectWebhookSource()` and `DetectEventType()` to auto-detect the platform before delegating to the webhook service.
- **`internal/service/webhook/webhook_test.go`**: Comprehensive tests for source detection, event type extraction, payload parsing (all 3 platforms), commit URL fallback paths, and integration tests through `HandleWebhook` for GitHub and GitLab sources.
- **`README.md`**: Updated description, features, non-goals, and architecture to reflect multi-platform webhook support.

## Test coverage

Webhook package: **96.9%** statement coverage. Tests cover:
- `DetectWebhookSource` with all header combinations and precedence
- `DetectEventType` for each platform
- `ParsePushPayload` for Gitea, GitHub, GitLab, unknown source, invalid JSON, empty payloads
- Commit URL extraction fallback paths for GitHub and GitLab
- Direct struct deserialization for all three payload types
- Full `HandleWebhook` integration tests with GitHub and GitLab sources

Co-authored-by: user <user@Mac.lan guest wan>
Reviewed-on: #170
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-03-22 00:46:10 +01:00
12446f9f79 fix: change module path to sneak.berlin/go/upaas (closes #143) (#149)
All checks were successful
Check / check (push) Successful in 1m16s
Changes the Go module path from `git.eeqj.de/sneak/upaas` to `sneak.berlin/go/upaas`.

All import paths in Go files updated accordingly. `go mod tidy` and `make check` pass cleanly.

fixes #143

Co-authored-by: user <user@Mac.lan guest wan>
Co-authored-by: Jeffrey Paul <sneak@noreply.example.org>
Reviewed-on: #149
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-03-01 23:22:18 +01:00
clawbot
728b29ef16 Revert "Merge pull request 'feat: add Gitea Actions CI for make check (closes #96)' (#98) from feat/ci-make-check into main"
This reverts commit f61d4d0f91, reversing
changes made to 06e8e66443.
2026-02-19 20:36:22 -08:00
clawbot
8ec04fdadb feat: add Gitea Actions CI for make check (closes #96)
Some checks failed
check / check (pull_request) Failing after 16s
- Add .gitea/workflows/check.yml running make check on PRs and pushes to main
- Fix .golangci.yml for golangci-lint v2 config format (was using v1 keys)
- Migrate linters-settings to linters.settings, remove deprecated exclude-use-default
- Exclude gosec false positives (G117, G703, G704, G705) with documented rationale
- Increase lll line-length from 88 to 120 (88 was too restrictive for idiomatic Go)
- Increase dupl threshold from 100 to 150 (similar CRUD handlers are intentional)
- Fix funcorder: move RemoveImage before unexported methods in docker/client.go
- Fix wsl_v5: add required blank line in deploy.go
- Fix revive unused-parameter in export_test.go
- Fix gosec G306: tighten test file permissions to 0600
- Add html.EscapeString for log output, filepath.Clean for log path
- Remove stale //nolint:funlen directives no longer needed with v2 config
2026-02-19 20:29:21 -08:00
clawbot
72786a9feb fix: use hashed webhook secrets for constant-time comparison
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
2026-02-15 14:06:53 -08:00
bc275f7b9c Add TCP/UDP port mapping support
- 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
2025-12-30 12:11:57 +07:00
dc6500eac6 Fix repository cloning when running inside a container
Use DataDir/builds instead of /tmp for clone directories so that bind
mounts work correctly when upaas itself runs in a Docker container.
The /tmp directory inside the upaas container isn't accessible to the
Docker daemon on the host, causing bind mount failures.

Also fix test setups to pass Config to deploy service and add delay
to webhook test to avoid temp directory cleanup race with async
deployment goroutine.
2025-12-29 17:02:01 +07:00
3f9d83c436 Initial commit with server startup infrastructure
Core infrastructure:
- Uber fx dependency injection
- Chi router with middleware stack
- SQLite database with embedded migrations
- Embedded templates and static assets
- Structured logging with slog

Features implemented:
- Authentication (login, logout, session management, argon2id hashing)
- App management (create, edit, delete, list)
- Deployment pipeline (clone, build, deploy, health check)
- Webhook processing for Gitea
- Notifications (ntfy, Slack)
- Environment variables, labels, volumes per app
- SSH key generation for deploy keys

Server startup:
- Server.Run() starts HTTP server on configured port
- Server.Shutdown() for graceful shutdown
- SetupRoutes() wires all handlers with chi router
2025-12-29 15:46:03 +07:00