Files
incredigo/internal/worklist/worklist.go
T
leetcrypt 71a74e7166 guide: read-only guided manual-rotation layer (links + worklist + TUI)
Advances the guided-rotation goal without rotating anything.

- internal/links: offline change-password URL generation — curated per-service
  table + RFC 8615 /.well-known/change-password + parent-domain fallback; derives
  a web host from a credential (git/netrc "user @ host", docker registry, aws)
- internal/worklist: secrets-free rotation worklist (source, identity, auto/manual,
  link) + Markdown renderer
- internal/tui: Bubble Tea walk-through (one credential per screen, open link,
  mark done/skip, progress) — READ-ONLY, enters/stores no secret
- cmd: `incredigo worklist` (offline, stdout/--out) and `incredigo guide` (TUI)
- tests: link derivation, worklist build/markdown + no-secret-column, TUI
  navigation/done/quit/view

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 14:58:23 -07:00

66 lines
2.1 KiB
Go

// Package worklist turns discovered credentials into a rotation worklist: per
// credential, whether it can be auto-rotated (a driver exists) or is manual, and
// the page to rotate it on. It contains NO secrets — only non-secret metadata and
// links — so a worklist is safe to write to disk or print.
package worklist
import (
"fmt"
"strings"
"incredigo/internal/discover"
"incredigo/internal/links"
"incredigo/internal/rotate"
)
// Item is one credential's rotation entry.
type Item struct {
Index int
Credential discover.Credential
Driver string // "" when no rotation driver handles it (manual)
Link links.Link
}
// Manual reports whether this credential has no automated rotation path today.
func (it Item) Manual() bool { return it.Driver == "" }
// Build classifies credentials (via the rotate registry) and attaches links.
// With no drivers registered every Item is Manual.
func Build(creds []discover.Credential) []Item {
plans := rotate.PlanAll(creds)
items := make([]Item, len(plans))
for i, p := range plans {
items[i] = Item{
Index: i + 1,
Credential: p.Credential,
Driver: p.Driver,
Link: links.LinkFor(p.Credential),
}
}
return items
}
// Markdown renders a worklist as a Markdown document (no secrets).
func Markdown(items []Item) string {
var b strings.Builder
b.WriteString("# incredigo rotation worklist\n\n")
fmt.Fprintf(&b, "%d credential(s). No secrets are included in this file.\n\n", len(items))
b.WriteString("| # | source | identity | rotation | change-password link |\n")
b.WriteString("|---|--------|----------|----------|----------------------|\n")
for _, it := range items {
rot := "manual"
if !it.Manual() {
rot = "auto: " + it.Driver
}
url := it.Link.URL
if url == "" {
url = "— (no web page)"
}
fmt.Fprintf(&b, "| %d | %s | %s | %s | %s |\n",
it.Index, it.Credential.Source, it.Credential.Identity, rot, url)
}
b.WriteString("\nGenerated by incredigo. Links are derived offline ")
b.WriteString("(curated table or RFC 8615 /.well-known/change-password).\n")
return b.String()
}