Implement Phase 1: core framework, operational tooling, and runbook
Core packages: crypto (Argon2id/AES-256-GCM), config (TOML/viper), db (SQLite/migrations), barrier (encrypted storage), seal (state machine with rate-limited unseal), auth (MCIAS integration with token cache), policy (priority-based ACL engine), engine (interface + registry). Server: HTTPS with TLS 1.2+, REST API, auth/admin middleware, htmx web UI (init, unseal, login, dashboard pages). CLI: cobra/viper subcommands (server, init, status, snapshot) with env var override support (METACRYPT_ prefix). Operational tooling: Dockerfile (multi-stage, non-root), docker-compose, hardened systemd units (service + daily backup timer), install script, backup script with retention pruning, production config examples. Runbook covering installation, configuration, daily operations, backup/restore, monitoring, troubleshooting, and security procedures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1
web/static/htmx.min.js
vendored
Normal file
1
web/static/htmx.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
24
web/static/style.css
Normal file
24
web/static/style.css
Normal file
@@ -0,0 +1,24 @@
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #f5f5f5; color: #333; line-height: 1.6; }
|
||||
.container { max-width: 800px; margin: 0 auto; padding: 2rem; }
|
||||
header h1 { margin-bottom: 2rem; }
|
||||
header h1 a { color: #333; text-decoration: none; }
|
||||
main { background: #fff; border-radius: 8px; padding: 2rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
|
||||
h2 { margin-bottom: 1rem; color: #222; }
|
||||
h3 { margin: 1.5rem 0 0.5rem; color: #444; }
|
||||
p { margin-bottom: 1rem; }
|
||||
.form-group { margin-bottom: 1rem; }
|
||||
.form-group label { display: block; margin-bottom: 0.25rem; font-weight: 600; }
|
||||
.form-group input { width: 100%; padding: 0.5rem; border: 1px solid #ccc; border-radius: 4px; font-size: 1rem; }
|
||||
button { padding: 0.5rem 1.5rem; background: #2563eb; color: #fff; border: none; border-radius: 4px; font-size: 1rem; cursor: pointer; }
|
||||
button:hover { background: #1d4ed8; }
|
||||
.error { background: #fee2e2; color: #991b1b; padding: 0.75rem; border-radius: 4px; margin-bottom: 1rem; }
|
||||
.badge { background: #dbeafe; color: #1e40af; padding: 0.125rem 0.5rem; border-radius: 4px; font-size: 0.875rem; }
|
||||
.status-bar { display: flex; gap: 1rem; align-items: center; padding: 0.75rem; background: #f9fafb; border-radius: 4px; margin-bottom: 1.5rem; flex-wrap: wrap; }
|
||||
.status-bar a { margin-left: auto; color: #2563eb; }
|
||||
table { width: 100%; border-collapse: collapse; margin: 0.5rem 0; }
|
||||
th, td { text-align: left; padding: 0.5rem; border-bottom: 1px solid #e5e7eb; }
|
||||
th { font-weight: 600; background: #f9fafb; }
|
||||
.admin-actions { margin-top: 0.5rem; }
|
||||
.admin-actions button { background: #dc2626; }
|
||||
.admin-actions button:hover { background: #b91c1c; }
|
||||
31
web/templates/dashboard.html
Normal file
31
web/templates/dashboard.html
Normal file
@@ -0,0 +1,31 @@
|
||||
{{define "title"}} - Dashboard{{end}}
|
||||
{{define "content"}}
|
||||
<h2>Dashboard</h2>
|
||||
<div class="status-bar">
|
||||
<span>Logged in as <strong>{{.Username}}</strong></span>
|
||||
{{if .IsAdmin}}<span class="badge">Admin</span>{{end}}
|
||||
<span>State: <strong>{{.State}}</strong></span>
|
||||
<a href="/login" onclick="fetch('/v1/auth/logout',{method:'POST'})">Logout</a>
|
||||
</div>
|
||||
|
||||
<h3>Engine Mounts</h3>
|
||||
{{if .Mounts}}
|
||||
<table>
|
||||
<thead><tr><th>Name</th><th>Type</th><th>Path</th></tr></thead>
|
||||
<tbody>
|
||||
{{range .Mounts}}
|
||||
<tr><td>{{.Name}}</td><td>{{.Type}}</td><td>{{.MountPath}}</td></tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<p>No engines mounted.</p>
|
||||
{{end}}
|
||||
|
||||
{{if .IsAdmin}}
|
||||
<h3>Admin Actions</h3>
|
||||
<div class="admin-actions">
|
||||
<button hx-post="/v1/seal" hx-confirm="Are you sure you want to seal the service?">Seal Service</button>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
17
web/templates/init.html
Normal file
17
web/templates/init.html
Normal file
@@ -0,0 +1,17 @@
|
||||
{{define "title"}} - Initialize{{end}}
|
||||
{{define "content"}}
|
||||
<h2>Initialize Metacrypt</h2>
|
||||
<p>Set the seal password for this Metacrypt instance. This password will be required to unseal the service after each restart.</p>
|
||||
{{if .Error}}<div class="error">{{.Error}}</div>{{end}}
|
||||
<form method="POST" action="/init">
|
||||
<div class="form-group">
|
||||
<label for="password">Seal Password</label>
|
||||
<input type="password" id="password" name="password" required autofocus>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="confirm">Confirm Password</label>
|
||||
<input type="password" id="confirm" name="confirm" required>
|
||||
</div>
|
||||
<button type="submit">Initialize</button>
|
||||
</form>
|
||||
{{end}}
|
||||
9
web/templates/initializing.html
Normal file
9
web/templates/initializing.html
Normal file
@@ -0,0 +1,9 @@
|
||||
{{define "title"}} - Initializing{{end}}
|
||||
{{define "content"}}
|
||||
<h2>Initializing...</h2>
|
||||
<p>Metacrypt is being initialized. Please wait.</p>
|
||||
<div hx-get="/v1/status" hx-trigger="every 2s" hx-swap="none"
|
||||
hx-on::after-request="if(JSON.parse(event.detail.xhr.responseText).state==='unsealed')window.location='/dashboard'">
|
||||
<p>Checking status...</p>
|
||||
</div>
|
||||
{{end}}
|
||||
20
web/templates/layout.html
Normal file
20
web/templates/layout.html
Normal file
@@ -0,0 +1,20 @@
|
||||
{{define "layout"}}<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Metacrypt{{block "title" .}}{{end}}</title>
|
||||
<script src="/static/htmx.min.js"></script>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1><a href="/">Metacrypt</a></h1>
|
||||
</header>
|
||||
<main>
|
||||
{{template "content" .}}
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>{{end}}
|
||||
21
web/templates/login.html
Normal file
21
web/templates/login.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{{define "title"}} - Login{{end}}
|
||||
{{define "content"}}
|
||||
<h2>Login</h2>
|
||||
<p>Authenticate with your MCIAS credentials.</p>
|
||||
{{if .Error}}<div class="error">{{.Error}}</div>{{end}}
|
||||
<form method="POST" action="/login">
|
||||
<div class="form-group">
|
||||
<label for="username">Username</label>
|
||||
<input type="text" id="username" name="username" required autofocus>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="totp_code">TOTP Code (if enabled)</label>
|
||||
<input type="text" id="totp_code" name="totp_code" autocomplete="one-time-code">
|
||||
</div>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
{{end}}
|
||||
13
web/templates/unseal.html
Normal file
13
web/templates/unseal.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{{define "title"}} - Unseal{{end}}
|
||||
{{define "content"}}
|
||||
<h2>Unseal Metacrypt</h2>
|
||||
<p>The service is sealed. Enter the seal password to unseal.</p>
|
||||
{{if .Error}}<div class="error">{{.Error}}</div>{{end}}
|
||||
<form method="POST" action="/unseal">
|
||||
<div class="form-group">
|
||||
<label for="password">Seal Password</label>
|
||||
<input type="password" id="password" name="password" required autofocus>
|
||||
</div>
|
||||
<button type="submit">Unseal</button>
|
||||
</form>
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user