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
2e9a00f182 KI-generierte Skill-Beschreibung im Bericht
Adds an AI-generated, factual German description ("Was macht dieser Skill?")
to scans and shows it in the report.

Changes:
- DB: new nullable `description` column on scansTable (lib/db schema; pushed via drizzle-kit).
- AI: new `generateSkillDescription()` in aiAnalysis.ts — reuses provider selection,
  token redaction, system prompt and JSON extraction; expects {"description": "..."},
  returns null and never throws on failure.
- Engine: scanEngine now generates the description independently of the AI findings
  rules — only a provider+token are required, so it works even when AI findings rules
  are disabled. Description failures do not break the scan. EngineResult gains
  aiDescription. (Provider/token error precedence unchanged for findings.)
- Prompt: new admin-editable "description" prompt (Beschreibungs-Anweisung) seeded via
  onConflictDoNothing, consistent with system/analysis prompts.
- Persist/serialize: description written on scan insert and returned in
  serializeScan (list + detail responses).
- API spec: added nullable `description` to the Scan schema in openapi.yaml; regenerated
  zod + react-query clients via orval codegen.
- Report UI: new "Was macht dieser Skill?" card in the report header (hidden when empty)
  and a matching section in the PDF/print export.

Notes / deviations:
- Old scans are not backfilled (per task scope); their description stays null and the
  section is hidden.
- Description is requested as JSON ({"description": ...}) to stay compatible with the
  existing "JSON only" system prompt.
- Verified: full typecheck passes, both workflows run, new prompt seeded, scans API
  returns description.

Replit-Task-Id: 40c4457b-54d1-4283-a336-478620c3afa8
2026-06-10 21:13:51 +00:00
amertensreplit
532f42117f Add automated tests for skill version detection
Task #13: lock in the fingerprint/relation logic behind SkillGuard's
identical/modified/new version detection with automated tests.

What was added
- Set up Vitest in artifacts/api-server (dev dep + `test` script + vitest.config.ts
  using the "workspace" resolve condition so @workspace/* resolve to source).
- Unit tests (no DB):
  - src/lib/skillFingerprint.test.ts — hashText/hashBytes stability & agreement,
    computeFingerprint stable + order-independent + sensitive to content/path/add/remove,
    jaccard overlap/symmetry/empty handling.
  - src/lib/lineDiff.test.ts — lineSimilarity ratios (identical, single-edit, disjoint,
    symmetric, CRLF), lineDiff context/add/remove with line numbers and the 2000-line cap.
- DB-backed tests (use the existing DATABASE_URL):
  - src/routes/relation.test.ts — computeRelation: identical content under a different
    name -> "identical" + check-counter (countFingerprint) increments; one-line edit to a
    single-file skill -> "modified" with sensible similarity; unrelated skill -> "new".
    Also direct computeContentSimilarity cases. Fixtures use randomized content to avoid
    collisions with shared dev data and are cleaned up afterEach.
  - src/routes/compare.test.ts — e2e GET /api/scans/:id/compare/:otherId via a live
    server: asserts unchanged/modified/added/removed statuses, sorted file order, the
    line diff for the modified file, null diffs elsewhere, and 404 for missing scans.

Production code change
- Exported computeRelation, computeContentSimilarity, countFingerprint from
  src/routes/scans.ts so the relation logic can be unit-tested. No behavior change.

Verification
- `pnpm --filter @workspace/api-server run test` -> 34 tests, 4 files, all pass.
- `pnpm --filter @workspace/api-server run typecheck` passes (rebuilt stale lib/db
  declarations via `pnpm run typecheck:libs`).
- Production build unaffected: esbuild only bundles from src/index.ts, so *.test.ts
  files are not included.

Replit-Task-Id: e9ae5e24-1480-4a09-8436-1718c535573a
2026-06-10 19:48:10 +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
Replit Agent
434ec07885 Add live progress updates and detailed scan checkpoints to scan results
Introduce streaming endpoint for NDJSON scan progress, incorporate scan checkpoints into scan details, and update UI components to display this new information.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 0d01f99a-ea6a-447d-82fd-311715434a39
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 2852b526-3bf8-4a93-a62a-a50e26291074
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/e32d2b99-1721-47dd-833c-98b372f48008/0d01f99a-ea6a-447d-82fd-311715434a39/8MCgDZm
Replit-Helium-Checkpoint-Created: true
2026-06-10 18:53:17 +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