Skip to content

Commit 2ee555a

Browse files
damacusclaude
andauthored
feat: Security workflows (#14)
* Install beads and resolve issues * fix: resolve E2E test failures caused by inherited hx-select on body The hx-select="#main-content" on <body> was inherited by all HTMX elements, causing modal fetches (bucket/user create) to select nothing from responses that don't contain #main-content. This resulted in modals never being inserted into the DOM. Changes: - Remove global hx-target/hx-select/hx-swap from body tag - Switch to Alpine.js CSP build with pinned version - Rewrite buckets dropdown from Alpine to vanilla JS - Fix browser upload progress modal visibility - Update E2E tests to use native Playwright clicks - Add template security tests enforcing best practices - Add MCP server config and CLAUDE.md symlink --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 031a864 commit 2ee555a

26 files changed

+888
-53
lines changed

.beads/.gitignore

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# SQLite databases
2+
*.db
3+
*.db?*
4+
*.db-journal
5+
*.db-wal
6+
*.db-shm
7+
8+
# Daemon runtime files
9+
daemon.lock
10+
daemon.log
11+
daemon.pid
12+
bd.sock
13+
sync-state.json
14+
last-touched
15+
16+
# Local version tracking (prevents upgrade notification spam after git ops)
17+
.local_version
18+
19+
# Legacy database files
20+
db.sqlite
21+
bd.db
22+
23+
# Worktree redirect file (contains relative path to main repo's .beads/)
24+
# Must not be committed as paths would be wrong in other clones
25+
redirect
26+
27+
# Merge artifacts (temporary files from 3-way merge)
28+
beads.base.jsonl
29+
beads.base.meta.json
30+
beads.left.jsonl
31+
beads.left.meta.json
32+
beads.right.jsonl
33+
beads.right.meta.json
34+
35+
# Sync state (local-only, per-machine)
36+
# These files are machine-specific and should not be shared across clones
37+
.sync.lock
38+
.jsonl.lock
39+
sync_base.jsonl
40+
export-state/
41+
42+
# NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here.
43+
# They would override fork protection in .git/info/exclude, allowing
44+
# contributors to accidentally commit upstream issue databases.
45+
# The JSONL files (issues.jsonl, interactions.jsonl) and config files
46+
# are tracked by git by default since no pattern above ignores them.

.beads/README.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Beads - AI-Native Issue Tracking
2+
3+
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
4+
5+
## What is Beads?
6+
7+
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
8+
9+
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
10+
11+
## Quick Start
12+
13+
### Essential Commands
14+
15+
```bash
16+
# Create new issues
17+
bd create "Add user authentication"
18+
19+
# View all issues
20+
bd list
21+
22+
# View issue details
23+
bd show <issue-id>
24+
25+
# Update issue status
26+
bd update <issue-id> --status in_progress
27+
bd update <issue-id> --status done
28+
29+
# Sync with git remote
30+
bd sync
31+
```
32+
33+
### Working with Issues
34+
35+
Issues in Beads are:
36+
- **Git-native**: Stored in `.beads/issues.jsonl` and synced like code
37+
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
38+
- **Branch-aware**: Issues can follow your branch workflow
39+
- **Always in sync**: Auto-syncs with your commits
40+
41+
## Why Beads?
42+
43+
**AI-Native Design**
44+
- Built specifically for AI-assisted development workflows
45+
- CLI-first interface works seamlessly with AI coding agents
46+
- No context switching to web UIs
47+
48+
🚀 **Developer Focused**
49+
- Issues live in your repo, right next to your code
50+
- Works offline, syncs when you push
51+
- Fast, lightweight, and stays out of your way
52+
53+
🔧 **Git Integration**
54+
- Automatic sync with git commits
55+
- Branch-aware issue tracking
56+
- Intelligent JSONL merge resolution
57+
58+
## Get Started with Beads
59+
60+
Try Beads in your own projects:
61+
62+
```bash
63+
# Install Beads
64+
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
65+
66+
# Initialize in your repo
67+
bd init
68+
69+
# Create your first issue
70+
bd create "Try out Beads"
71+
```
72+
73+
## Learn More
74+
75+
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
76+
- **Quick Start Guide**: Run `bd quickstart`
77+
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
78+
79+
---
80+
81+
*Beads: Issue tracking that moves at the speed of thought*

.beads/config.yaml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Beads Configuration File
2+
# This file configures default behavior for all bd commands in this repository
3+
# All settings can also be set via environment variables (BD_* prefix)
4+
# or overridden with command-line flags
5+
6+
# Issue prefix for this repository (used by bd init)
7+
# If not set, bd init will auto-detect from directory name
8+
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
9+
# issue-prefix: ""
10+
11+
# Use no-db mode: load from JSONL, no SQLite, write back after each command
12+
# When true, bd will use .beads/issues.jsonl as the source of truth
13+
# instead of SQLite database
14+
# no-db: false
15+
16+
# Disable daemon for RPC communication (forces direct database access)
17+
# no-daemon: false
18+
19+
# Disable auto-flush of database to JSONL after mutations
20+
# no-auto-flush: false
21+
22+
# Disable auto-import from JSONL when it's newer than database
23+
# no-auto-import: false
24+
25+
# Enable JSON output by default
26+
# json: false
27+
28+
# Default actor for audit trails (overridden by BD_ACTOR or --actor)
29+
# actor: ""
30+
31+
# Path to database (overridden by BEADS_DB or --db)
32+
# db: ""
33+
34+
# Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON)
35+
# auto-start-daemon: true
36+
37+
# Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE)
38+
# flush-debounce: "5s"
39+
40+
# Export events (audit trail) to .beads/events.jsonl on each flush/sync
41+
# When enabled, new events are appended incrementally using a high-water mark.
42+
# Use 'bd export --events' to trigger manually regardless of this setting.
43+
# events-export: false
44+
45+
# Git branch for beads commits (bd sync will commit to this branch)
46+
# IMPORTANT: Set this for team projects so all clones use the same sync branch.
47+
# This setting persists across clones (unlike database config which is gitignored).
48+
# Can also use BEADS_SYNC_BRANCH env var for local override.
49+
# If not set, bd sync will require you to run 'bd config set sync.branch <branch>'.
50+
# sync-branch: "beads-sync"
51+
52+
# Multi-repo configuration (experimental - bd-307)
53+
# Allows hydrating from multiple repositories and routing writes to the correct JSONL
54+
# repos:
55+
# primary: "." # Primary repo (where this database lives)
56+
# additional: # Additional repos to hydrate from (read-only)
57+
# - ~/beads-planning # Personal planning repo
58+
# - ~/work-planning # Work planning repo
59+
60+
# Integration settings (access with 'bd config get/set')
61+
# These are stored in the database, not in this file:
62+
# - jira.url
63+
# - jira.project
64+
# - linear.url
65+
# - linear.api-key
66+
# - github.org
67+
# - github.repo

.beads/interactions.jsonl

Whitespace-only changes.

.beads/issues.jsonl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{"id":"ironbuckets-1is","title":"Pin third-party CDN assets to immutable versions","description":"Replace mutable CDN references (@latest, 3.x.x) with explicit versions and add tests to prevent regression.","status":"closed","priority":2,"issue_type":"task","owner":"dan.webb@damacus.io","created_at":"2026-02-09T21:47:28.504938Z","created_by":"Dan Webb","updated_at":"2026-02-09T21:54:03.726755Z","closed_at":"2026-02-09T21:54:03.726755Z","close_reason":"Pinned mutable CDN script references to explicit versions and added regression tests to prevent @latest/3.x.x usage."}
2+
{"id":"ironbuckets-5hj","title":"Add baseline security response headers","description":"Implement server-level security headers middleware (X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, and HSTS when HTTPS). Add tests.","status":"open","priority":1,"issue_type":"task","owner":"dan.webb@damacus.io","created_at":"2026-02-09T21:47:28.439513Z","created_by":"Dan Webb","updated_at":"2026-02-09T21:47:28.439513Z"}
3+
{"id":"ironbuckets-ef2","title":"Introduce CSP compatible with current templates and remove easy inline JS hotspots","description":"Add a Content-Security-Policy header and reduce inline-script/event-handler usage where low-risk, preserving app behavior. Add regression tests.","status":"closed","priority":2,"issue_type":"task","owner":"dan.webb@damacus.io","created_at":"2026-02-09T21:47:37.736295Z","created_by":"Dan Webb","updated_at":"2026-02-09T21:54:03.720101Z","closed_at":"2026-02-09T21:54:03.720101Z","close_reason":"Introduced CSP via security middleware and aligned interactive templates with CSRF-aware request wiring while preserving existing UI behavior."}
4+
{"id":"ironbuckets-q5x","title":"Harden auth cookie flags and clearing semantics","description":"Set Secure based on request security context and ensure logout clearing cookie uses matching attributes (Path, SameSite, Secure, MaxAge). Add handler tests.","status":"closed","priority":1,"issue_type":"task","owner":"dan.webb@damacus.io","created_at":"2026-02-09T21:47:28.449391Z","created_by":"Dan Webb","updated_at":"2026-02-09T21:49:10.68477Z","closed_at":"2026-02-09T21:49:10.68477Z","close_reason":"Implemented secure-context cookie handling with consistent logout clearing attributes and added auth handler tests."}
5+
{"id":"ironbuckets-tfa","title":"Add CSRF protection for state-changing routes","description":"Enable CSRF middleware and ensure HTMX requests include CSRF token header. Add tests for allowed/blocked POST behavior.","status":"closed","priority":1,"issue_type":"task","owner":"dan.webb@damacus.io","created_at":"2026-02-09T21:47:28.455923Z","created_by":"Dan Webb","updated_at":"2026-02-09T21:54:03.733698Z","closed_at":"2026-02-09T21:54:03.733698Z","close_reason":"Added CSRF middleware for interactive state-changing requests and template-side HTMX CSRF token header propagation with tests."}

.beads/metadata.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"database": "beads.db",
3+
"jsonl_export": "issues.jsonl"
4+
}

.mcp.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"mcpServers": {
3+
"github": {
4+
"command": "npx",
5+
"args": ["-y", "@modelcontextprotocol/server-github"],
6+
"env": {
7+
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
8+
}
9+
},
10+
"git": {
11+
"command": "uvx",
12+
"args": ["mcp-server-git", "--repository", "."]
13+
},
14+
"context7": {
15+
"command": "npx",
16+
"args": ["-y", "@upstash/context7-mcp@latest"]
17+
}
18+
}
19+
}

AGENTS.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,3 +188,29 @@ Run `task --list` to see all available tasks. Key ones:
188188
5. **Use existing patterns**—follow the code style already in the codebase
189189
6. **Run linting**—ensure code passes `golangci-lint`
190190
7. **Document changes**—update relevant docs when adding features
191+
192+
## Landing the Plane (Session Completion)
193+
194+
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
195+
196+
**MANDATORY WORKFLOW:**
197+
198+
1. **File issues for remaining work** - Create issues for anything that needs follow-up
199+
2. **Run quality gates** (if code changed) - Tests, linters, builds
200+
3. **Update issue status** - Close finished work, update in-progress items
201+
4. **PUSH TO REMOTE** - This is MANDATORY:
202+
```bash
203+
git pull --rebase
204+
bd sync
205+
git push
206+
git status # MUST show "up to date with origin"
207+
```
208+
5. **Clean up** - Clear stashes, prune remote branches
209+
6. **Verify** - All changes committed AND pushed
210+
7. **Hand off** - Provide context for next session
211+
212+
**CRITICAL RULES:**
213+
- Work is NOT complete until `git push` succeeds
214+
- NEVER stop before pushing - that leaves work stranded locally
215+
- NEVER say "ready to push when you are" - YOU must push
216+
- If push fails, resolve and retry until it succeeds

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../AGENTS.md

cmd/server/main.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ func main() {
2121
log.Printf("MINIO_ENDPOINT not set, using default: %s", minioEndpoint)
2222
}
2323

24+
e := newServer(minioEndpoint)
25+
26+
// Start Server
27+
e.Logger.Fatal(e.Start(":8080"))
28+
}
29+
30+
func newServer(minioEndpoint string) *echo.Echo {
2431
e := echo.New()
2532

2633
// Services
@@ -44,6 +51,8 @@ func main() {
4451
},
4552
}))
4653
e.Use(middleware.Recover())
54+
e.Use(customMiddleware.SecurityHeaders())
55+
e.Use(customMiddleware.CSRF())
4756
// Apply auth middleware globally - it will skip public routes internally
4857
e.Use(customMiddleware.AuthMiddleware(authService))
4958

@@ -136,6 +145,5 @@ func main() {
136145
e.POST("/settings/restart", settingsHandler.RestartService)
137146
e.GET("/settings/logs", settingsHandler.GetLogs)
138147

139-
// Start Server
140-
e.Logger.Fatal(e.Start(":8080"))
148+
return e
141149
}

0 commit comments

Comments
 (0)