Commit graph

7 commits

Author SHA1 Message Date
amertensreplit
9415e184dc Add on-demand AI description generation for existing scans
Task #24: Older scans created before description generation existed showed an
empty "Was macht dieser Skill?" section. Users can now trigger description
generation for any existing scan from the report.

Changes:
- OpenAPI: added POST /scans/{id}/description (operationId generateScanDescription)
  returning ScanDetail (200), ApiError (404 not found, 422 cannot generate).
  Regenerated api-zod and api-client-react via codegen.
- api-server (routes/scans.ts): new route loads the scan, its stored files, the
  enabled provider and prompts, reconstructs ParsedFile[] from scan_files
  (binary files -> empty content/isBinary), calls existing
  generateSkillDescription(), persists description and returns full ScanDetail.
  Clean 422 errors when no provider / no token / generation yields nothing; the
  scan is never mutated on failure.
- skillguard (scan-report.tsx): the description card now always renders; when no
  description exists it shows a "Beschreibung erzeugen" button wired to the new
  mutation, with loading state, toast feedback, and query cache update on success.

Incidental fix: the dev/test database was missing the `scans.description` column
(schema drift from the earlier description task). Ran drizzle-kit push to sync;
this unblocked 5 previously failing api-server tests. All 59 tests now pass and
full typecheck is green.

Rebase: one conflict in scan-report.tsx import line — main added the `ShieldAlert`
icon (new KI-disclaimer Alert), this branch added `Loader2`. Resolved by keeping
both icons; the rest of the file (disclaimer Alert + new description card) merged
cleanly. No semantic divergence.

Replit-Task-Id: 0610af4f-aa62-434e-abcd-d742081b6459
2026-06-11 01:25:35 +00:00
amertensreplit
f44c3ed247 Guided AI provider setup with model discovery
Task: Replace free-text model entry in Admin → Providers with a guided
flow (Name → API type → API endpoint → API token → Test connection) that
auto-discovers available models after a successful connection test and
presents them in a Select positioned right after the API endpoint field.

Model-independent connection test (key fix):
- The setup connection test no longer requires a model, removing the
  chicken-and-egg where discovery could never run. test-connection's model
  is now optional: when a model is supplied it does a full chat round-trip;
  when omitted it verifies credentials via the provider's models endpoint and
  reports how many models are available. The form sends no model on the
  initial test, so a successful test now reliably triggers discovery.

Backend:
- aiAnalysis.ts: added listProviderModels(provider) — GETs {baseUrl}/models
  using Bearer auth for openai/custom and x-api-key + anthropic-version for
  anthropic. Normalizes data[].id (falls back to models[].id/.name),
  dedupes + sorts, and redacts secrets in error messages via the existing
  redactSecrets helper.
- providers.ts: added POST /providers/list-models accepting ad-hoc config
  (apiType, baseUrl, optional apiToken, optional providerId). Falls back to
  the stored token by providerId when token omitted; returns { ok, models,
  message } and never leaks the token.

API contract:
- openapi.yaml: added /providers/list-models path, ProviderListModelsInput
  and ProviderModelsResult schemas. Regenerated zod + react-query client via
  the api-spec codegen workflow (orval).

Admin UI (admin.tsx):
- New ModelField component renders a loading state, a Select when models are
  discovered, or a manual free-text input fallback (with hint) when discovery
  returns nothing — so saving always works for custom endpoints.
- Field order follows the guided flow: Name → API type → API endpoint →
  API token → Test connection, with the model selector appearing after the
  token once discovery succeeds. A successful test automatically triggers
  discovery; editing endpoint or token resets discovery state.

Verified: workspace typecheck passes, api-server tests 59/59 pass, live curl
of the new endpoint returns graceful errors without leaking the token.

Replit-Task-Id: 8d300a47-0b45-4677-9e9e-aa041bf03e98
2026-06-10 21:13:35 +00:00
amertensreplit
54323706b5 Add skill version timeline (fingerprint lineage)
Task #14: show a full version timeline for each skill family, not just the
single most-similar prior scan.

What changed:
- OpenAPI spec (lib/api-spec/openapi.yaml): new GET /scans/{id}/lineage
  (operationId getScanLineage) returning an array of ScanLineageEntry
  (id, name, verdict, riskScore, relation, similarity, comparedScanId,
  fingerprint, createdAt). Regenerated api-zod + api-client-react via codegen.
- API (artifacts/api-server/src/routes/scans.ts): new lineage endpoint.
  Builds an undirected graph over all scans linked by the comparedScanId chain
  AND identical (non-empty) fingerprints, then BFS-walks the connected
  component containing the requested scan and returns it newest-first. Works
  purely from existing data, no re-scanning. 404 for unknown ids.
- UI (artifacts/skillguard/src/pages/scan-report.tsx): new VersionTimeline
  card rendering the family as a vertical timeline; each entry shows verdict,
  relation badge, similarity, risk score and date. The viewed scan is marked
  "Aktuell angezeigt"; every other entry links to the existing comparison view
  /vergleich/{viewedId}/{entryId}. Card hidden when the family has <=1 member.

Notes:
- Lineage = connected component, so any member returns the full family.
- Verified end-to-end locally (created new/modified/identical chain, checked
  lineage ordering + 404, confirmed timeline + compare links in the UI),
  then deleted the test scans.

Replit-Task-Id: c7f87ce6-59d8-4396-b16b-f20846f42f0b
2026-06-10 19:47:39 +00:00
amertensreplit
ba9788a93c Add Skill-Fingerprint database & report comparison
Each scan gets a deterministic overall fingerprint (SHA-256 over sorted
path+fileHash pairs) plus per-file SHA-256 hashes and stored text content
(binary: hash+size only). On upload the skill is always re-scanned and
classified vs prior scans as new / identical / modified, with a per-fingerprint
check counter, a "most similar known skill" link, and a file-level diff view.

Deviations from the plan:
- Relation matching keys off shared file *paths* (Jaccard over paths, tie-break
  on hashes), not hash-Jaccard alone, which is always 0 for single-file edits
  (text paste = one SKILL.md) and would mis-class every edited single-file skill
  as "new". Similarity is content-aware: identical files = 1.0, changed text
  files use line-level LCS ratio, added/removed/changed-binary = 0.
- parseText no longer uses the display name as the file path (fixed "SKILL.md")
  so identical pastes with different names are "identical", not "modified".

Backend: skillFingerprint.ts, lineDiff.ts (+lineSimilarity), skillParser.ts
(per-file hash+isBinary), routes/scans.ts (computeRelation, content similarity,
checkCount, comparedScan, GET /scans/:id/compare/:otherId). DB: scans
fingerprint/relation/similarity/comparedScanId (+index), scan_files hash/content.
API spec + orval codegen regenerated. UI: fingerprint card + compare link on
report, relation badges in history, new /vergleich/:id/:otherId page with
side-by-side summaries and expandable line diff. German UI, no emojis.

Verified end-to-end against the running API and screenshotted both UI pages;
test data cleaned up afterward.

Code-review fix: relation classification no longer relies on path-Jaccard
(every text paste shares path SKILL.md, so unrelated pastes were falsely
linked as "modified"). computeRelation now selects the candidate by
content-aware similarity and only returns "modified" when similarity >= 40
or a file is byte-identical; otherwise "new". Updated OpenAPI similarity
description; removed now-unused jaccard import.

Replit-Task-Id: 79a8e472-6635-493c-8995-3233ba7df75c
2026-06-10 19:34:46 +00:00
amertensreplit
543fd96afd Verbindungscheck beim Provider-Einrichten (Task #10)
Add an inline "Verbindung testen" button to the Neuer/Bearbeiten provider
dialogs so users can test a connection with the currently entered values
before saving.

Backend:
- New endpoint POST /providers/test-connection that accepts an ad-hoc provider
  config (apiType, baseUrl, model, optional apiToken, optional providerId) in
  the request body and runs a one-shot test via the existing callProvider
  logic. When apiToken is empty and providerId is given, it falls back to the
  stored token of that provider (edit case). Returns { ok, message }; the token
  is never returned or leaked (existing redactSecrets still applies to errors).
- Defined ProviderTestConnectionInput schema + path in openapi.yaml and ran
  codegen for Zod schemas and the React client.

Frontend (artifacts/skillguard/src/pages/admin.tsx):
- Add dialog: "Verbindung testen" button (disabled until Base URL + Token set
  or while testing) with loading spinner and an inline green success / red
  error result box. Result resets when the dialog closes.
- Edit dialog: same inline test; empty token field falls back to the stored
  token via providerId. Result resets on open/close.
- The existing per-card "Verbindung testen" button is unchanged.

Verification: typecheck passes for api-server and skillguard; curl tested the
new endpoint for success-path (fetch error surfaced), empty-token, and invalid
body (400) cases. Token not present in any response.

Deviations: none.
Replit-Task-Id: 4f77293f-468c-496a-ab05-1f10e7bf8137
2026-06-10 18:54:56 +00:00
Replit Agent
a70b0d580a SkillGuard: complete frontend wiring and harden backend
Original task: build "SkillGuard", a German web app to audit agent skills on
two axes (IT-Sicherheit, Datenschutz) with static rule engine + Replit-independent
AI analysis configured via an admin backend.

This session:
- Fixed frontend TS errors: lucide-react name collisions (Badge from ui, Activity
  from lucide), widened apiType to AiProviderApiType, added queryKey to useGetScan.
- Verified all pages render in German (Dashboard, Prüfen, Bericht, Verlauf, Admin)
  and the full scan flow works end-to-end (malicious sample -> verdict block).

Code-review-driven hardening:
- POST /api/scans now returns the full ScanDetail (files + findings) to match the
  OpenAPI contract, instead of only the summary.
- AI provider error bodies are redacted (token, Bearer, sk- patterns) before being
  returned/persisted, and provider fetches now have a 60s timeout.
- ZIP parsing now enforces limits (max files, total + per-file size) to mitigate
  zip-bomb DoS.

Updated replit.md (project overview, decisions, gotchas) and added a memory note
on lucide-react icon name collisions.
2026-06-08 14:59:17 +00:00
Replit Agent
2246770e5b Initial commit 2026-05-28 23:37:31 +00:00