Skip to content

Password lock UI (#13) - #16

Open
ableinc wants to merge 1 commit into
mainfrom
agent/issue-13-password-lock-ui
Open

Password lock UI (#13)#16
ableinc wants to merge 1 commit into
mainfrom
agent/issue-13-password-lock-ui

Conversation

@ableinc

@ableinc ableinc commented Aug 26, 2026

Copy link
Copy Markdown
Owner

Closes #13

What the agent did

Committed as 59a27a7, and the correct pre-configured harness identity (coding-agent-loop[bot]) was used.

Summary

Implemented the approved plan for issue #13 — an optional server.password that gates the control API and web console, with a session token kept in sessionStorage (so closing the tab logs the operator out) and no changes to today's behavior when the password is left blank.

Files changed:

  • internal/config/config.go — added ServerConfig.Password; config.example.json and README.md updated to document it ("" = disabled).
  • internal/server/auth.go (new) — sessionStore (token issue/valid/revoke, 12h sliding TTL, 10-failures/min login throttle), authEnabled(), and constant-time credential comparison accepting either a live session token or the raw configured password.
  • internal/server/server.gorequireAuth middleware (allow-list: /healthz, /auth, /login, /, /ui/*), new GET /auth, POST /login, POST /logout handlers, and getConfig now redacts server.password and reports password_set.
  • internal/web/assets/{index.html,app.css,app.js} — lock-screen overlay, a Lock button, sessionStorage-based token storage, authHeaders() merged into every apiFetch call (including the one raw transcript fetch), 401 handling that clears the token and re-locks, and a boot() sequence driven by GET /auth.
  • Tests added in internal/config/config_test.go, internal/server/server_test.go (auth-required/allow-list, login/logout, token reuse, raw-password-as-bearer, throttling, config redaction, and an explicit "no password → every route open" regression), and internal/web/web_test.go.
  • README.md — config table, sample config, route table, and the "Web interface" section updated per the plan.

Verification: go build ./..., go vet ./..., and go test ./... all pass except two pre-existing failures in internal/git (TestWorktreeLifecycle, TestEnsureRepoAppliesIdentityOverridingGlobalConfig) — that package was never touched by this change; the failures are an environment/git-identity artifact of this sandbox, not a regression from this work.

Note on the environment: local Go tooling required GOPATH=/tmp/gopath to download the go1.26.5 toolchain pinned by go.mod (the default ~/go/pkg/sumdb path is read-only in this sandbox). This is only a local verification workaround and required no repository changes.

Worth a reviewer's second look: the two "decisions the reviewer may want to overrule" from the plan — accepting the raw password as a bearer credential (keeps curl one-shot but puts the password on the wire on every call) and /ui/* assets being served unauthenticated (required so the lock screen itself can render).

Verification

Tests failed (make test). This PR is a draft — the failure is reported rather than hidden, so you can judge whether the change is salvageable.

Test output (tail)
go test -race ./...
go: golang.org/toolchain@v0.0.1-go1.26.5.linux-arm64: verifying module: golang.org/toolchain@v0.0.1-go1.26.5.linux-arm64: open /home/node1/go/pkg/sumdb/sum.golang.org/latest: read-only file system
make: *** [Makefile:115: test] Error 1

Changes

README.md                      |  27 +++++++-
 config.example.json            |   3 +-
 internal/config/config.go      |   8 ++-
 internal/config/config_test.go |  18 +++++
 internal/server/auth.go        | 135 ++++++++++++++++++++++++++++++++++++++
 internal/server/server.go      |  79 +++++++++++++++++++++-
 internal/server/server_test.go | 145 +++++++++++++++++++++++++++++++++++++++++
 internal/web/assets/app.css    |  57 ++++++++++++++++
 internal/web/assets/app.js     | 115 ++++++++++++++++++++++++++++++--
 internal/web/assets/index.html |  10 +++
 internal/web/web_test.go       |  22 +++++++
 11 files changed, 604 insertions(+), 15 deletions(-)

Opened automatically by coding-agent-loop (run 13d5a39a-e5c7-43d3-b133-c5307d79f4fa, attempt 2, model claude-sonnet-5, cost $2.6031, session 46e18e3d-3452-40df-9c35-2c72d59ca8fd). Nothing here has been reviewed by a human yet.

server.password, when set, requires it (or a session token obtained via
POST /login) for every route except /healthz, /auth, /login, /, and /ui/*.
The browser console stores its session token in sessionStorage, so closing
the tab or browser logs the operator out; a daemon restart invalidates
every session since tokens are held only in memory. Empty password (the
default) keeps today's open behaviour unchanged.

Closes #13.
@ableinc ableinc mentioned this pull request Aug 26, 2026
@ableinc
ableinc marked this pull request as ready for review August 26, 2026 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Password lock UI

1 participant