Skip to content

feat(ci): add SLSA L1 npm provenance attestation (OWASP A03) - #133

Open
SabaTech-dev wants to merge 91 commits into
boticlaw:mainfrom
SabaTech-dev:feat/slsa-l1-provenance
Open

feat(ci): add SLSA L1 npm provenance attestation (OWASP A03)#133
SabaTech-dev wants to merge 91 commits into
boticlaw:mainfrom
SabaTech-dev:feat/slsa-l1-provenance

Conversation

@SabaTech-dev

Copy link
Copy Markdown

Qué

  • Add SLSA L1 provenance attestation workflow for npm packages
  • Add verification workflow for PRs
  • Add CI workflow with lint, test, build jobs

Por qué

OWASP 2025 A03: Supply Chain Failures requires verifiable provenance for npm packages. SLSA L1 ensures packages have signed provenance attestations.

Changes

  • provenance.yml: Attests npm packages using actions/attest-build-provenance@v2
  • verify-provenance.yml: Verifies attestations on PRs
  • ci.yml: Added lint, test, build jobs

Tests

  • Workflow syntax validated
  • Provenance attestation will generate on next push to main

Edge Cases

  • Requires id-token: write permission for OIDC signing
  • Requires NPM_TOKEN secret for npm publish with provenance
  • Provenance artifacts retained for 90 days

Alfred added 30 commits March 23, 2026 19:57
…after upstream merge

- 8 custom pages: actions, calendar, costs-alerts, handoffs, live, morning, notepad, workflows
- 10 custom API routes: costs-alerts/config, costs-alerts/usage, debug, debug/secret, debug/validate, handoffs, live, morning/brief, morning/system, notepad
- 9 AlfredMC components: ActivityRow, AgentRow, CronRow, Dock, MetricCard, SectionHeader, StatusBar, TopBar, index
- 6 agent sprites: main, coder, debug, research, security, refactor-expert
- 4 critical fixes reapplied: gateway scopes, sessions JSON filter, transcript regex, terminal validation
- Systemd: fixed ExecStart (next start, not next dev), added EnvironmentFile
- next.config: removed turbopack root override causing build failures
- Fixed transcript route to correctly map session key → sessionId
- Now reads sessions.json to lookup sessionId from session key
- Uses correct path: /agents/main/sessions/{sessionId}.jsonl
- Added authentication using requireAuth from @/lib/auth-helpers
- Added comprehensive tests for auth and input validation
- Improved session key validation with stricter pattern

Closes: transcript-route-refactor
…ndpoints

Phase 1 of systematic auth rollout (Option B).

Protected endpoints:
- /api/agents/config (HIGH risk - exposes agent config)
- /api/agents/status (MEDIUM risk)
- /api/agents/workload (MEDIUM risk)

Using requireAuth() helper from auth-helpers.ts.
Skipped: gateway/status, live, telemetry, models (read-only, low risk).

Related: MC Security: Protect Unauthenticated Endpoints
- Add requireAuth mock returning authorized: true
- Pass mock NextRequest to GET() handler
Fix TypeError: agent.model.split is not a function in dashboard.
agent.model can be {primary, fallbacks} object or string. Created
getModelDisplayName() helper in src/lib/model-utils.ts and applied
across 7 components: DashboardClient, AgentsClient, morning page,
AgentOrganigrama, AgentInspectPanel, AgentPanel, SystemInfo.
SECURITY:
- Added middleware.ts to enforce authentication on all dashboard routes
- Pages redirect to /login, API routes return 401
- Public routes: /login, /api/auth/*, /api/health, /api/heartbeat/tasks, /api/kanban/agent/*, /office, /reports/[token], static assets
- Agent auth paths (/api/heartbeat/*, /api/kanban/agent/*) pass through to route-level auth

BRANDING:
- Replaced all 'Carlos' references → 'Joker' in workflows/page.tsx
- Replaced 'Tenacitas' → 'Alfred' in workflows/page.tsx
- Zero remaining references to Carlos, Tenacitas, SuperBotijo, or Botijo

UI FIX:
- About section avatar: replaced next/image fill with explicit width/height
- Prevents image from rendering full-size in viewport
…api/auth/*

- Simplified middleware: only /login and /api/auth/* are public
- Added auth to /api/health endpoint (was exposing system info)
- All 26 page routes → 307 redirect to /login
- All 28 API routes → 401 without auth, 200 with auth
- Verified: login works, protected access works, wrong password rejected
33 references across src/ replaced from original SuperBotijo author path
to actual server path. Zero 'daniel' references remaining.
ICONS:
- Regenerated all icon sizes (16-512px) from Alfred logo.png
- logo-small.png, favicon-16x16/32x32/192x192, apple-touch-icon
- android-chrome-192x192/512x512, icon-192/512

CHAT FIX:
- checkGatewayStatus() now uses HTTP /health instead of WebSocket
- WebSocket auth was failing with 'pairing required' after gateway restart
- HTTP health check is lightweight and doesn't require device pairing
- Chat is now writable (readOnly: false, gateway: available)
- SuperBotijo → Alfred Mission Control across 20 .md files
- Carlos Azaustre/Tenacitas → Alfred/Joker
- /home/daniel paths → /home/ubuntu
- SUPERBOTIJO_* env vars → MISSION_CONTROL_*
- Archived: FUNCIO.md, README_ADDITION.md, design-system/
- Attribution to original SuperBotijo project preserved in READMEs
- Fixed OPENCLAW_DIR default: /root/.openclaw → /home/ubuntu/.openclaw
- Fixed DB path: auto-detect from script location
- Renamed SUPERBOTIJO_DB → MISSION_CONTROL_DB
- Added mtime-based delta: only processes modified files
- Added batch SQL inserts for performance
- Added 50MB file size limit to prevent timeout
- System cron: every 5 minutes (sessions + messages, staggered 30s)
- Result: 3907 activities synced (3346 messages + 210 sessions + 100 tasks + 3 commands)
- Remove 'server-only' import from pricing.ts (breaks CLI scripts)
- Fix OPENCLAW_DIR default: /root/.openclaw → /home/ubuntu/.openclaw
- Add missing aliases: glm-4.6v, xiaomi/mimo-v2-pro, free model variants
- Cron: /etc/cron.d/alfred-mc-usage-collect (every 15 min)
- Dashboard now shows real cost data: $1.61 today across 6 agents
1. Removed 'server-only' import from pricing.ts (blocked CLI execution)
2. Fixed OPENCLAW_DIR default: /root/.openclaw → /home/ubuntu/.openclaw
3. Fixed double provider prefix in getModelsFromOpenClawConfig()
   (openrouter/openrouter/xiaomi/mimo-v2-pro → openrouter/xiaomi/mimo-v2-pro)
4. getUsedModels() now includes agent fallbacks (not just primary)
5. Added legacy openrouter/minimax/minimax-m2.5 to pricing constants

Cron: /etc/cron.d/alfred-mc-usage-collect (every 15 min)
Result: $0.87 today, 13 snapshots, zero 'unknown model' warnings
…ring

- Create PerformanceClient.tsx client component for performance dashboard
- Add /api/performance endpoint to serve monitor results and baseline data
- Include response time comparison, baseline variation, and log viewer
- Fix build error (missing @/components/PerformanceClient import)
- Performance monitor now connects successfully (all endpoints OK)
- Add baseline results and monitor scripts from Phase 1
…provements

- Alert system (alert-system.js): severity levels (INFO/WARN/CRITICAL),
  persistence to JSON, rolling window of 200 alerts, category filtering
- Historical tracker (historical-tracker.js): rolling window of 2880 data
  points (~24h at 30s), trend analysis with degradation detection
- Performance monitor v2: integrates alert + history, graceful Lighthouse
  skip after first failure (fixes noisy ERROR logs every 30s)
- New API endpoints: /api/performance/alerts (with level/category filters),
  /api/performance/history (with trend summary per endpoint)
- Dashboard overhaul: tabbed UI (Overview/Alerts/History), sparkline charts,
  trend stats (avg/min/max), alert feed with severity badges, temporal
  evolution table
- 13 new tests for alert-system and historical-tracker (29 total perf tests)
- Build: ✅ 615 passing (3 pre-existing failures for @testing-library/dom)
…ars, connection status

- LiveStatusIndicator component: 3 animation modes (pulse/blink/wave),
  Web Animations API for smooth rendering, configurable size/speed
- Live page overhaul: summary cards (sessions, tokens in/out, total),
  token proportion bars per session, connection indicator (Wifi icon),
  status transition flash animation, time-ago labels, poll counter
- Fixed TopBar usage of LiveStatusIndicator in Alfred/ and AlfredMC/
- Build: ✅ passing
…ignore hardening

- Added requireAuth() to /api/system/performance, /api/system/backups, /api/system/uptime
- All 3 endpoints now return 401 without valid Bearer token or auth cookie
- Added auth denial test (13/13 performance tests pass)
- Removed /api/debug/secret and /api/debug/validate (exposed AUTH_SECRET prefix)
- Added src/app/api/debug/ to .gitignore
- Updated tests to mock auth-helpers
Task: MC-Tab /mission — Mission Statement Page (4cc7c19c)

Created /mission route that assembles MissionCard + mission-storage:

- page.tsx: Server component loads mission via getMission(), passes to client
- actions.ts: Server actions for saveMissionAction + resetMissionAction with revalidatePath
- MissionPageClient.tsx: Client component with full CRUD UI
  * View mode: renders MissionCard component (existing)
  * Edit mode: textarea for statement, tag-based goals/values with add/remove
  * Save/Reset actions via server actions
  * Auto-opens edit mode when no mission exists
  * Responsive (mobile-first, max-w-4xl container)
  * i18n support via useI18n hook
  * Confirmation dialog before reset
  * Loading states on save/reset

No auth changes. No MissionCard rewrites. No new API routes.

Build: clean (0 errors)
MC runs as systemd user service, so systemctl needs --user flag to
discover and query services correctly. Without it, /logs tab was broken.

Files changed:
- src/app/api/system/monitor/route.ts — systemctl is-active --user
- src/app/api/system/services/route.ts — list-units/list-unit-files --user
- src/app/api/logs/stream/route.ts — list-units/list-unit-files --user
- src/operations/service-discovery-ops.ts — list-units/list-unit-files --user
- src/operations/system-monitor-ops.ts — systemctl is-active --user
- src/lib/system-stats.ts — systemctl is-active --user
- src/lib/terminal-command.ts — allow --user flag in systemctl whitelist
- src/lib/system-stats.test.ts — update test mocks to match --user calls
Dashboard was loading in 7.2s because page.tsx awaited telemetry data
(blocking execFileSync calls) before SSR. Now:

- page.tsx passes initialTelemetry={null} — no blocking SSR
- DashboardClient shows loading skeleton while telemetry loads
- Telemetry fetches client-side via /api/telemetry/dashboard (already polling every 15s)
- SSR is now instant (no await)

Files changed:
- src/app/(dashboard)/page.tsx — removed getInitialTelemetry() await
- src/app/(dashboard)/DashboardClient.tsx — nullable initialTelemetry, loading skeleton
Skills tab was loading 1MB+ payload in SSR because all skills including
fullContent were fetched server-side. Now:

- page.tsx: no SSR data fetching, instant render
- GET /api/skills: added ?page=&limit=&search=&source= params
  * Strips fullContent from listing (summary mode by default)
  * Supports server-side search and source filtering
  * Returns pagination metadata (page, limit, total, totalPages)
- GET /api/skills/[id]: new endpoint for full skill details on-demand
- SkillsClient.tsx:
  * Loads skills client-side with pagination (50 per page)
  * Debounced search (300ms) via server-side filtering
  * fullContent loaded on-demand when user clicks a skill
  * Pagination controls (Prev/Next with page indicator)
  * Loading skeleton while fetching
  * Loading indicator for skill detail modal

Payload reduction: ~1MB+ → <50KB per page (estimated)
MC-Tab: /projects — Projects Dashboard Page (fdd150bb)

Created /projects route that displays all projects with statistics:

- page.tsx: Server Component loads projects via kanban-db, calculates progress
- ProjectsClient.tsx: Client Component with full UI
  * Grid layout (responsive: 1/2/3 columns mobile/tablet/desktop)
  * Filters by status (all/active/completed/paused)
  * Shows project name, description, progress bar, task count
  * Status badges with color coding (active=accent, completed=success, paused=info)
  * Last updated timestamp
  * Loading state
  * Empty state when no projects match filter

Uses existing /api/projects endpoint (no API changes).

Build: clean
MC-Tab: /journal — Journal Operations Page (023bdef0)

Created /journal route with full CRUD using existing components:

- page.tsx: Server Component loads entries via kanban-db
- JournalClient.tsx: Client Component with full UI
  * Ensambla JournalTimeline, JournalFilters, JournalEditorModal existentes
  * GET /api/journal con filtros startDate/endDate
  * POST /api/journal para crear entradas nuevas
  * PUT /api/journal/[id] para actualizar
  * DELETE /api/journal/[id] para eliminar
  * Botón "Nueva Entrada" abre modal
  * Editar/eliminar cada entrada (JournalEntryCard)
  * Filtros por rango de fechas con botón "Aplicar"
  * Responsive (mobile + tablet + desktop)

Usa API existente sin modificaciones.

Build: clean
MC-Tab: /activity — Activity Feed Page (326a2b5)

Created /activity route with monitoring capabilities:

- page.tsx: Server Component (empty - client-side rendering)
- ActivityClient.tsx: Client Component
  * ActivityHeatmap (GitHub-style 30-day activity map)
  * Filtros por estado (todos/exitosos/errores/pendientes)
  * ActivityFeed con 50 actividades más recientes
  * Filtros reactivos - reload al cambiar filtro
- Modified ActivityFeed.tsx: Añadidos props status + agent

Usa API existente /api/activities con query params.

Build: clean
MC-Tab: /calendar — Weekly Calendar Page (54ab3773)

Created /calendar route with weekly task calendar:

- page.tsx: Server Component con header + WeeklyCalendar existente
- WeeklyCalendar.tsx ya existe (componente completo con navegación por semanas)
  * Navegación: semana anterior/siguiente/volver a hoy
  * Vista de 7 días x 24 horas (grid)
  * Filtra tareas de /api/tasks (cron + heartbeat + scheduled)
  * Muestra tareas como cards con iconos tipo/estado
  * Color-coding por estado (success=green, error=red, running=yellow, pending=gray)

Usa API existente /api/tasks sin modificaciones.

Build: clean
Alfred and others added 30 commits May 24, 2026 15:22
- SwarmClient.tsx: Complete UI with tasks table, agents sidebar, create modal
- SwarmClient.tsx: Auto-refresh polling every 10s
- SwarmClient.tsx: Status and agent filters
- SwarmClient.tsx: Uses AMC proxy routes instead of direct Swarm API
- API proxy: /api/swarm/tasks (GET/POST) and /api/swarm/tasks/[id] (GET/PATCH/DELETE)
- API proxy: /api/swarm/health and /api/swarm/agents (already existed)
- swarm-proxy.ts: Shared proxy utility with timeout and error handling
- i18n: Added filter translations (EN/ES)
- .env: Added SWARM_API_URL and SWARM_API_KEY configuration
- Dock: /swarm tab already present in agents section
- Build: Next.js build successful
- SwarmClient now uses credentials:include for browser session auth
- All fetch calls use AMC proxy routes (/api/swarm/*)
- Proxy verified working: health, tasks, agents all return 200
- Build successful
Lead scraper completo movido desde workspace/scripts/lead-scraper:
- Normalizer: toLead() schema unificado
- Scrapers: Malt + Workana con Cheerio (sin Playwright)
- Scoring Engine: 0-100 con regex extraction
- ICP Filter: threshold + keywords + skill/budget matching
- Telegram Alerts: alerts configurables por score
- Pipeline: processLead() integra score → filter → send → alert
- MCP Server v0 + Dashboard + Monitoring
- 60/60 tests PASS

Co-authored-by: OpenCode
…n-Control repo

- HIGH-001: Remove child_process import from mcp-server/index.js
- MEDIUM-001: Remove AGENT_KEY hardcoded fallback in http-server.js + monitoring/index.js
- LOW-001: Add source parameter validation (F-011) in http-server.js run_scraper endpoint

All 3 files pass node --check syntax validation.

Note: Previous fixes were applied to wrong repo (scripts/lead-scraper vs Alfred-Mission-Control/scrapers/lead-scraper)
Preserved changes from amc/ copy before cleanup:
- 47 source files with uncommitted modifications
- Includes: middleware, auth, JWT, auto-enforce, pipeline, tests
- Created: 2026-06-02T12:07:23Z

This commit ensures no work is lost during deduplication.
Workspace/ had local modifications that conflicted with amc/ merge.
Preserving here to ensure clean merge from VPS migration copy.
Conflict resolution strategy:
- Source code (src/, scripts/): accepted amc/ (more recent)
- Build configs (package.json, next.config.mjs): accepted amc/
- Lock files: accepted amc/
- Local runtime files: kept workspace/

All changes from VPS migration now integrated into workspace/ copy.
- Create /actions page with ActionsClient component (quick actions: heartbeat, usage-stats, git-status, clear-temp, restart-gateway, npm-audit)
- Create /api/cron-jobs/route.ts as re-export alias of /api/cron/route.ts
- Add actions.title and actions.subtitle i18n keys (en + es)
- All routes verified: /api/cron-jobs returns 401 (correct), /actions returns 307 redirect to login (correct)
- Build passes: 0 errors
… expand REPORT_DIRS

- Copy 39 cierre-del-dia, 7 evening-agenda, and 47 ai-social-digest reports
  from Alfred_Reports_Docs/ to reports/cron/ (VPS migration gap)
- Expand REPORT_DIRS from 10 to 25 entries covering ALL cron directories
- Add type mappings for all new subdirectories in getReportType()
- Reports tabs now show historical data correctly
- Add /api/mission/route.ts for mission CRUD operations
- Import and render MissionCard at top of HeartbeatStatus
- Support optional mission prop (shows card when available)
- Mission persists to data/mission.json

Completes roadmap item 14.2: Mission card in HeartbeatStatus
- system-health page now fetches live data from /api/health every 30s
- Grouped by category: Core, LLM, Services, Dev
- Overall status bar with up/total count + uptime + last refresh
- Added 9 missing services to stack-health checks: browserless, langfuse, qmd-mcp, llama.cpp-gpu/embed, searxng, engram, pr-agent, osint-nexus
- Real-time auto-refresh + manual refresh button
canConnectTcpAny() tries 127.0.0.1 and 192.168.1.39. checkHttpService() falls back to alt IP. Fixes false DOWN for llama.cpp-gpu, llama.cpp-embed, searxng.
- Add mission category to suggestions types
- Create suggestions-scoring-mission.ts with 4 analyzers:
  - Mission setup suggestion when no mission defined
  - Mission enrichment (goals/values) suggestions
  - Mission review suggestion after 30 days
  - Task alignment suggestion when <30% tasks linked to projects
- Integrate mission analyzer into main suggestions engine
- Add MissionStats interface to suggestions types

Completes: 14.3 Integration Mission context en Suggestions Engine
…tbeat-ops through HeartbeatTab

- Add mission field to HeartbeatStatus interface in heartbeat-ops
- Import getMission in heartbeat-ops and include in returned data
- Pass mission prop through HeartbeatTab to HeartbeatStatus component
- Remove redundant getMission import from cron page
- Roadmap item 14.2 deferred: Mission card en HeartbeatStatus → DONE
- Add floating name labels above each agent desk (emoji + name + role)
- Update monitor lines to show identity (role, emoji) instead of generic status
- Mark Office3D identity and Heartbeat identity roadmap items as complete
- Build verified (next build exit 0)
- Add provenance.yml with attest-build-provenance for npm packages
- Add verify-provenance.yml for PR verification
- Add ci.yml with lint, test, build jobs
- Implements SLSA L1 supply chain security requirement
- NOTE: Requires NPM_TOKEN secret for npm publish with provenance
- PRs verify attestation exists on base branch commit
- Prevents false negatives from merge commit SHAs
- Verified with actionlint
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.

1 participant