Commit Graph

10 Commits

Author SHA1 Message Date
forbes
e92c022e80 feat(auth): add authentication, RBAC, API tokens, and default admin
Add a complete authentication and authorization system to Silo with
three pluggable backends (local bcrypt, LDAP/FreeIPA, OIDC/Keycloak),
session management, API token support, and role-based access control.

Authentication backends:
- Local: bcrypt (cost 12) password verification against users table
- LDAP: FreeIPA simple bind with group-to-role mapping
- OIDC: Keycloak redirect flow with realm role mapping
- Backends are tried in order; users upserted to DB on first login

Session and token management:
- PostgreSQL-backed sessions via alexedwards/scs + pgxstore
- Opaque API tokens (silo_ prefix, SHA-256 hashed, shown once)
- 24h session lifetime, HttpOnly/SameSite=Lax/Secure cookies

Role-based access control (admin > editor > viewer):
- RequireAuth middleware: Bearer token -> session -> redirect/401
- RequireRole middleware: per-route-group minimum role enforcement
- CSRF protection via justinas/nosurf on web forms, API exempt
- CORS locked to configured origins when auth enabled

Route restructuring:
- Public: /health, /ready, /login, /auth/oidc, /auth/callback
- Web (auth + CSRF): /, /projects, /schemas, /settings
- API read (viewer): GET /api/**
- API write (editor): POST/PUT/PATCH/DELETE /api/**

User context wiring:
- created_by/updated_by columns on items, projects, relationships
- All create/update handlers populate tracking fields from context
- CSV and BOM import handlers pass authenticated username
- Revision creation tracks user across all code paths

Default admin account:
- Configurable via auth.local.default_admin_username/password
- Env var overrides: SILO_ADMIN_USERNAME, SILO_ADMIN_PASSWORD
- Idempotent: created on first startup, skipped if exists

CLI and FreeCAD plugin:
- silo token create/list/revoke subcommands (HTTP API client)
- FreeCAD SiloClient sends Bearer token on all requests
- Token read from ApiToken preference or SILO_API_TOKEN env var

Web UI:
- Login page (Catppuccin Mocha themed, OIDC button conditional)
- Settings page with account info and API token management
- User display name, role badge, and logout button in header
- One-time token display banner with copy-to-clipboard

Database (migration 009):
- users table with role, auth_source, oidc_subject, password_hash
- api_tokens table with SHA-256 hash, prefix, expiry, scopes
- sessions table (scs pgxstore schema)
- audit_log table (schema ready for future use)
- created_by/updated_by ALTER on items, relationships, projects

New dependencies: scs/v2, scs/pgxstore, go-oidc/v3, go-ldap/v3,
justinas/nosurf, golang.org/x/oauth2
2026-01-31 11:20:12 -06:00
Zoe Forbes
c778825eb0 Add Silo mode toggle, SSL cert browsing, and BOM menu integration
- Silo_ToggleMode: checkable toolbar button that swaps Ctrl+O/S/N
  between standard FreeCAD file commands and Silo equivalents
- _swap_shortcuts() helper stores/restores original QAction shortcuts
- SSL settings: add CA certificate file browser (SslCertPath preference)
  with QFileDialog for .pem/.crt/.cer, loaded in _get_ssl_context()
- Integrate Silo_BOM into workbench toolbar (after upstream BOM merge)
- Add Silo_ToggleMode to toolbar as first item with separator
2026-01-31 09:21:48 -06:00
Zoe Forbes
3a79d89ec9 feat: add BOM system with API, database repository, and FreeCAD workbench command
Implement the full Bill of Materials stack on top of the existing
relationships table and bom_single_level view from migration 001.

API endpoints (6 new routes under /api/items/{partNumber}/bom):
- GET    /bom              Single-level BOM for an item
- GET    /bom/expanded     Multi-level BOM via recursive CTE (depth param)
- GET    /bom/where-used   Reverse lookup: which parents use this item
- POST   /bom              Add child to BOM with quantity, ref designators
- PUT    /bom/{child}      Update relationship type, quantity, ref des
- DELETE /bom/{child}       Remove child from BOM

Database layer (internal/db/relationships.go):
- RelationshipRepository with full CRUD operations
- Single-level BOM query joining relationships with items
- Multi-level BOM expansion via recursive CTE (max depth 20)
- Where-used reverse lookup query
- Cycle detection at insert time to prevent circular BOMs
- BOMEntry and BOMTreeEntry types for denormalized query results

Server wiring:
- Added RelationshipRepository to Server struct in handlers.go
- Registered BOM routes in routes.go under /{partNumber} subrouter

FreeCAD workbench (pkg/freecad/silo_commands.py):
- 9 new BOM methods on SiloClient (get, expanded, where-used, add,
  update, delete)
- Silo_BOM command class with two-tab dialog:
  - BOM tab: table of children with Add/Edit/Remove buttons
  - Where Used tab: read-only table of parent assemblies
- Add sub-dialog with fields for part number, type, qty, unit, ref des
- Edit sub-dialog pre-populated with current values
- Remove with confirmation prompt
- silo-bom.svg icon matching existing toolbar style
- Command registered in InitGui.py toolbar

No new migrations required - uses existing relationships table and
bom_single_level view from 001_initial.sql.
2026-01-31 08:09:26 -06:00
Zoe Forbes
8e44ed2f75 Fix SIGSEGV: defer document open after dialog close
Opening documents (especially assemblies) inside the QDialog nested
event loop can crash FreeCAD when the Assembly solver triggers during
document restore. Move FreeCAD.openDocument() to after dialog.exec_()
returns.
2026-01-29 22:42:15 -06:00
Zoe Forbes
e2b3f128c6 Fix API URL: only auto-append /api for bare hostnames
Use urllib.parse to check if the URL has a path component. Only append
/api when the path is empty (e.g. https://silo.kindred.internal).
URLs that already include a path (e.g. http://localhost:8080/api) are
left unchanged. Restore localhost placeholder as the default.
2026-01-29 22:27:10 -06:00
Zoe Forbes
559f61514c Fix API URL handling and SSL certificate verification
- Auto-append /api to base URL if not already present, so users can
  enter just the hostname (e.g. https://silo.kindred.internal)
- Load system CA certificate bundle in SSL context so the bundled
  Python trusts internal CAs (FreeIPA) without disabling verification
- Update settings dialog placeholder and hint text to clarify expected
  URL format
2026-01-29 22:26:26 -06:00
forbes
f08ecc14ea feat(workbench): fix icon loading and add settings dialog
Replace hardcoded FreeCAD addon path searches with __file__-relative
resolution for icons in both InitGui.py and silo_commands.py. Icons now
load correctly regardless of install location.

Add Silo_Settings command with URL and SSL verification fields. Settings
persist via FreeCAD preferences and take priority over env vars. Wire
SSL context into all SiloClient HTTP methods.
2026-01-29 19:28:11 -06:00
53b5edb25f update documentation and specs 2026-01-29 13:10:12 -06:00
Zoe Forbes
7f375fec7c Add revision control and project tagging migration 2026-01-24 16:27:18 -06:00
Zoe Forbes
ed9cef67f9 update databasing system with minimum API, schema parsing and FreeCAD
integration
2026-01-24 15:03:17 -06:00