Initial import.
This commit is contained in:
124
.golangci.yaml
Normal file
124
.golangci.yaml
Normal file
@@ -0,0 +1,124 @@
|
||||
# golangci-lint configuration for a security-critical IAM system.
|
||||
# Principle: fail loudly. Security and correctness issues are errors, not warnings.
|
||||
|
||||
run:
|
||||
timeout: 5m
|
||||
# Include test files so security rules apply to test helpers too.
|
||||
tests: true
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
enable:
|
||||
# --- Correctness ---
|
||||
# Unhandled errors are silent failures; in auth code they become vulnerabilities.
|
||||
- errcheck
|
||||
# go vet: catches printf-verb mismatches, unreachable code, suspicious constructs.
|
||||
- govet
|
||||
# Detects assignments whose result is never used; dead writes hide logic bugs.
|
||||
- ineffassign
|
||||
# Reports code that is never executed.
|
||||
- deadcode
|
||||
# Detects variables and functions that are never used.
|
||||
- unused
|
||||
|
||||
# --- Error handling ---
|
||||
# Enforces proper error wrapping (errors.Is/As instead of == comparisons) and
|
||||
# prevents accidental discard of wrapped sentinel errors.
|
||||
- errorlint
|
||||
# Detects returning (nil, nil) from functions that return (value, error), which
|
||||
# is almost always a logic error in auth flows.
|
||||
- nilnil
|
||||
|
||||
# --- Security ---
|
||||
# Primary security scanner: hardcoded secrets, weak RNG, insecure crypto
|
||||
# (MD5/SHA1/DES/RC4), SQL injection, insecure TLS, file permission issues, etc.
|
||||
- gosec
|
||||
# Deep static analysis: deprecated APIs, incorrect mutex use, unreachable code,
|
||||
# incorrect string conversions, and hundreds of other checks.
|
||||
- staticcheck
|
||||
# Detects integer overflow-prone conversions (e.g., int64 → int32) that can
|
||||
# corrupt length or index calculations in crypto/auth code.
|
||||
- gosimple
|
||||
|
||||
# --- Style / conventions (per CLAUDE.md) ---
|
||||
# Enforces gofmt formatting. Non-formatted code is a CI failure.
|
||||
- gofmt
|
||||
# Manages import grouping and formatting; catches stray debug imports.
|
||||
- goimports
|
||||
# Enforces Go naming conventions and exported-symbol documentation.
|
||||
- revive
|
||||
|
||||
linters-settings:
|
||||
errcheck:
|
||||
# Treat blank-identifier assignment of errors as a failure: `_ = riskyCall()`
|
||||
check-blank: true
|
||||
# Also check error returns from type assertions.
|
||||
check-type-assertions: true
|
||||
|
||||
govet:
|
||||
# Enable all analyzers, including shadow (variable shadowing is dangerous in
|
||||
# auth code where an outer `err` may be silently clobbered).
|
||||
enable-all: true
|
||||
|
||||
gosec:
|
||||
# Treat all gosec findings as errors, not warnings.
|
||||
severity: medium
|
||||
confidence: medium
|
||||
excludes:
|
||||
# G104 (errors unhandled) overlaps with errcheck; let errcheck own this.
|
||||
- G104
|
||||
|
||||
errorlint:
|
||||
errorf: true
|
||||
asserts: true
|
||||
comparison: true
|
||||
|
||||
gofmt:
|
||||
simplify: true
|
||||
|
||||
revive:
|
||||
rules:
|
||||
- name: exported
|
||||
severity: warning
|
||||
- name: error-return
|
||||
severity: error
|
||||
- name: error-strings
|
||||
severity: warning
|
||||
- name: if-return
|
||||
severity: warning
|
||||
- name: increment-decrement
|
||||
severity: warning
|
||||
- name: var-naming
|
||||
severity: warning
|
||||
- name: package-comments
|
||||
severity: warning
|
||||
- name: range
|
||||
severity: warning
|
||||
- name: time-naming
|
||||
severity: warning
|
||||
- name: unexported-return
|
||||
severity: error
|
||||
- name: indent-error-flow
|
||||
severity: warning
|
||||
- name: early-return
|
||||
severity: warning
|
||||
|
||||
issues:
|
||||
# Do not cap the number of reported issues; in security code every finding matters.
|
||||
max-issues-per-linter: 0
|
||||
max-same-issues: 0
|
||||
|
||||
# Exclude vendor and generated code only.
|
||||
exclude-dirs:
|
||||
- vendor
|
||||
exclude-files:
|
||||
- ".*\\.pb\\.go$"
|
||||
- ".*_gen\\.go$"
|
||||
|
||||
exclude-rules:
|
||||
# In test files, allow hardcoded test credentials (gosec G101) since they are
|
||||
# intentional fixtures, not production secrets.
|
||||
- path: "_test\\.go"
|
||||
linters:
|
||||
- gosec
|
||||
text: "G101"
|
||||
74
CLAUDE.md
Normal file
74
CLAUDE.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# CLAUDE.md
|
||||
|
||||
## Project Overview
|
||||
|
||||
MCIAS (Metacircular Identity and Access System) is a single-sign-on (SSO) and Identity & Access Management (IAM) system for personal projects. The target audience is a single developer building personal apps, with support for onboarding friends onto those apps.
|
||||
|
||||
**Priorities (in order):** security, robustness, correctness. Performance is secondary.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **Language:** Go
|
||||
- **Database:** SQLite
|
||||
- **Logging/Utilities:** git.wntrmute.dev/kyle/goutils
|
||||
- **Crypto:** Ed25519 (signatures), Argon2 (password hashing)
|
||||
- **Tokens:** JWT signed with Ed25519 (algorithm: EdDSA); always validate the `alg` header on receipt — never accept `none` or symmetric algorithms
|
||||
- **Auth:** Username/password + optional TOTP; future FIDO/Yubikey support
|
||||
|
||||
## Binaries
|
||||
|
||||
- `mciassrv` — authentication server (REST API over HTTPS/TLS)
|
||||
- `mciasctl` — admin CLI for account/token/credential management
|
||||
|
||||
## Development Workflow
|
||||
|
||||
If PROGRESS.md does not yet exist, create it before proceeding. It is the source of truth for current state.
|
||||
|
||||
1. Check PROGRESS.md for current state and next steps
|
||||
2. Define discrete next steps with actionable acceptance criteria
|
||||
3. Implement, adversarially verify correctness, write tests
|
||||
4. Commit to git, update PROGRESS.md
|
||||
5. Repeat
|
||||
|
||||
## Security Constraints
|
||||
|
||||
This is a security-critical project. The following rules are non-negotiable:
|
||||
|
||||
- Never implement custom crypto. Use standard library (`crypto/...`) or well-audited packages only.
|
||||
- Always validate the `alg` header in JWTs before processing; reject `none` and any non-EdDSA algorithm.
|
||||
- Argon2id parameters must meet current OWASP recommendations; never reduce them for convenience.
|
||||
- Credential storage (passwords, tokens, secrets) must never appear in logs, error messages, or API responses.
|
||||
- Any code touching authentication flows, token issuance/validation, or credential storage must include a comment citing the rationale for each security decision.
|
||||
- When in doubt about a crypto or auth decision, halt and ask rather than guess.
|
||||
- Review all crypto primitives against current best practices before use; flag any deviation in the commit body.
|
||||
|
||||
## Testing Requirements
|
||||
|
||||
- Tests live alongside source in the same package, using the `_test.go` suffix
|
||||
- Run with `go test ./...`; CI must pass with zero failures
|
||||
- Unit tests for all exported functions and security-critical internal functions
|
||||
- Integration tests for all subsystems (database layer, token issuance, auth flows)
|
||||
- End-to-end tests for complete login, token renewal, and revocation flows
|
||||
- Adversarially verify all outputs: test invalid inputs, boundary conditions, and known attack patterns (e.g., JWT `alg` confusion, timing attacks on credential comparison)
|
||||
- Use `crypto/subtle.ConstantTimeCompare` wherever token or credential equality is checked
|
||||
|
||||
## Git Commit Style
|
||||
|
||||
- First line: single line, max 55 characters
|
||||
- Body (optional): bullet points describing work done
|
||||
- Security-sensitive changes (crypto primitives, auth flows, token handling, credential storage, session management) must be explicitly flagged in the commit body with a `Security:` line describing what changed and why it is safe
|
||||
|
||||
## Go Conventions
|
||||
|
||||
- Format all code with `gofmt` before committing
|
||||
- Lint with `golangci-lint`; resolve all warnings unless explicitly justified
|
||||
- Wrap errors with `fmt.Errorf("context: %w", err)` to preserve stack context
|
||||
- Prefer explicit error handling over panics; never silently discard errors
|
||||
- Use `log/slog` (or goutils equivalents) for structured logging; never `fmt.Println` in production paths
|
||||
|
||||
## Key Documents
|
||||
|
||||
- `PROJECT.md` — Project specifications and requirements
|
||||
- `ARCHITECTURE.md` — **Required before any implementation.** Covers token lifecycle, session management, multi-app trust boundaries, and database schema. Do not generate code until this document exists.
|
||||
- `PROJECT_PLAN.md` — Discrete implementation steps (to be written)
|
||||
- `PROGRESS.md` — Development progress tracking (to be written)
|
||||
69
PROJECT.md
Normal file
69
PROJECT.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# MCIAS
|
||||
|
||||
We are building a single-signon and IAM system for personal projects.
|
||||
|
||||
## Background
|
||||
|
||||
The Metacircular Identity and Access System (MCIAS) provides standard
|
||||
tools for user and access management among metacircular and wntrmute
|
||||
systems.
|
||||
|
||||
In particular, the target audience is a single developer building
|
||||
personal apps. It should be easy to use MCIAS to facilitate onboarding
|
||||
friends onto these personal apps.
|
||||
|
||||
MCIAS is a foundational security and identity system. As such, the
|
||||
highest priorities are for security, robustness, and correctness.
|
||||
Performance is secondary, and can be tuned later.
|
||||
|
||||
## Specifications
|
||||
|
||||
+ Applications should be able to either do an interactive login, using a
|
||||
username/password (and potentially a TOTP), or present a token.
|
||||
+ Applications should be able to renew the token, which would nominally
|
||||
expire after some period (defaulting to maybe 30 days).
|
||||
+ There are two kinds of users: human and system accounts.
|
||||
+ System accounts can only present a token; they have a single token
|
||||
associated with that account at a time.
|
||||
+ User accounts have roles associated with them.
|
||||
+ Users with the admin role can issue tokens for any app, or users with
|
||||
the role named the same as a service account can issue tokens for that
|
||||
service account.
|
||||
+ Admin users can also revoke tokens for a service account.
|
||||
+ Service accounts (and users with the a role named the same as the
|
||||
service account) can also retrieve Postgres database credentials for
|
||||
the service account.
|
||||
+ Human accounts should eventually support FIDO logins and Yubikey auth,
|
||||
but the first pass only needs username, password, and optional TOTP.
|
||||
|
||||
## Technical details
|
||||
|
||||
+ User passwords will be stored using scrypt.
|
||||
+ The service account tokens and user/password authentication can be
|
||||
used to obtain a JWT, if that is appropriate.
|
||||
+ All authentication events should be logged.
|
||||
+ This service should use the packages contained in
|
||||
git.wntrmute.dev/kyle/goutils for logging etc.
|
||||
+ The database should be sqlite.
|
||||
+ Modern cryptography should be used. Preference should be given to
|
||||
Ed25519 as the public algorithm for signatures, for example. Consider
|
||||
the use of Argon2 for password hashes.
|
||||
|
||||
## Interfaces
|
||||
|
||||
+ The primary interface will be an REST API over HTTPS. TLS security is
|
||||
critical for this.
|
||||
+ We will also need to build client libraries in several languages
|
||||
later on.
|
||||
+ There should be two command line tools associated with MCIAS:
|
||||
+ mciassrv is the authentication server.
|
||||
+ mciasctl is the tool for admins to create and manage accounts, issue
|
||||
or revoke tokens, and manage postgres database credentials.
|
||||
|
||||
## Notes
|
||||
|
||||
+ We need an explicit security model.
|
||||
+ This is a system for small, personal services. Manual user lifecycle
|
||||
managment is acceptable and expected. Federation is an explicit
|
||||
nongoal.
|
||||
+ Strong testing is a requirement.
|
||||
31
README.md
Normal file
31
README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
The project notes are in PROJECT.md.
|
||||
|
||||
Before starting the project, read the project description and develop a
|
||||
system architecture document (ARCHITECTURE.md). It should describe the
|
||||
technical design of the system. Then, PROJECT_PLAN.md should be written
|
||||
that describes how to build this system in discrete steps.
|
||||
|
||||
Commit these files to Git after human review. For this project, all git
|
||||
commits should have a single first line, no more than 55 characters,
|
||||
that succinctly describes an overview of the changes. As necessary, the
|
||||
body of the commit message should contain bullets describing the work
|
||||
that was done.
|
||||
|
||||
Then, create PROGRESS.md. This should be initialized with the first
|
||||
steps for the project.
|
||||
|
||||
The development process for this should generally be:
|
||||
|
||||
1. Determine the current state of the project. Track the progress in
|
||||
PROGRESS.md, explicitly stating what was done and next steps.
|
||||
2. Develop reasonable, discrete next steps to move forward with
|
||||
actionable acceptance criteria.
|
||||
3. Complete the next steps.
|
||||
+ You should adversarially check whether any outputs are correct.
|
||||
+ All code units should be thoroughly unit tested.
|
||||
+ All subsystems should be thoroughly integration tested.
|
||||
+ Where appropriate, end-to-end tests to validate the system should
|
||||
be developed.
|
||||
4. Checkpoint your work, committing it to git.
|
||||
|
||||
Repeat this cycle until the system is in the desired end state.
|
||||
Reference in New Issue
Block a user