1
0
Fork
You've already forked prism
0
web frontend for cleave
  • JavaScript 61.5%
  • Go 28.9%
  • HTML 8.2%
  • Shell 1%
  • Makefile 0.3%
  • Other 0.1%
Thomas Stromberg c98ef4c631 degraded mode
2026年07月13日 08:07:24 -04:00
hacks
media
scripts
static allow PURL searches 2026年07月11日 13:32:24 +02:00
templates degraded mode 2026年07月13日 08:07:24 -04:00
testdata
.gitignore
.golangci.yml
.yamllint
aggregate_test.go
atom.go improve description 2026年07月09日 10:54:20 +02:00
atom_test.go dedup trait chips 2026年07月09日 19:13:54 +02:00
biome.json
breaker.go
cache_refresh_test.go
challenge.go
challenge_test.go
context.go pid-based galaxy views 2026年07月08日 17:53:52 +02:00
context_render_test.go pid-based galaxy views 2026年07月08日 17:53:52 +02:00
context_test.go Support parent-id relationships 2026年07月07日 21:51:50 +02:00
doc.go
download_test.go
file_view.go
file_view_test.go
filter_normalize_test.go allow PURL searches 2026年07月11日 13:32:24 +02:00
go.mod update hopper 2026年07月11日 13:32:53 +02:00
go.sum update hopper 2026年07月11日 13:32:53 +02:00
hero.go Filter heros by 99% 2026年07月09日 17:27:05 +02:00
hero_test.go allow PURL searches 2026年07月11日 13:32:24 +02:00
integration_test.go
litmus_test.go
litmus_v5_test.go
litmus_v6_test.go
main.go degraded mode 2026年07月13日 08:07:24 -04:00
Makefile
malecule.go pid-based galaxy views 2026年07月08日 17:53:52 +02:00
malecule_test.go pid-based galaxy views 2026年07月08日 17:53:52 +02:00
metrics.go
preview_gen_test.go
ratelimit.go
ratelimit_test.go
README.md
reassemble_test.go
rescan_test.go add hopper rescan API support 2026年07月07日 09:48:55 +02:00
result_template_test.go Add reference data 2026年07月10日 03:11:06 -04:00
reuseport_freebsd.go
reuseport_unix.go
scan_sync_test.go lint 2026年07月03日 22:51:01 +02:00
stamp_gradient_test.go
tree.go pid-based galaxy views 2026年07月08日 17:53:52 +02:00
tree_test.go pid-based galaxy views 2026年07月08日 17:53:52 +02:00
verdict_tip_test.go
zz_chroma_repro_test.go

prism

prism

Prism is the public-facing web frontend for the atomdrift malware-analysis pipeline — it powers https://lab.atomdrift.org/.

It is a read-mostly rendering layer: it serves the sample feed, per-file analysis pages, the inline source viewer, and AI reverse-engineering reports by reading from the hopper database (the sample registry and cached litmus analysis results) and streaming file bytes from hopper-api. Browser uploads, when enabled, are analyzed by a litmus server and the result is published back to hopper.

Prism holds no durable state of its own — it is a cache in front of hopper, so it can run anywhere. In production it runs in a FreeBSD jail (see Deployment) behind a Cloudflare Tunnel.

Build & run

make build
PORT=8080 ./prism

make dev runs a local build against the production hopper-db and hopper-api (browsing is read-only, but write actions hit prod — see the Makefile for the exact environment and ~/.pgpass requirement). make dev-watch does the same with auto-reload via air.

Configuration

Flags win over the matching environment variable.

Flag Env Default Purpose
--port PORT 8080 HTTP listen port
--db HOPPER_DSN / FALLOUT_DB postgres://hopper@hopper-db:5432/hopper?sslmode=disable hopper PostgreSQL DSN
--hopper-api-addr HOPPER_API_ADDR hopper-api:8081 hopper-api host:port (file bytes)
--litmus LITMUS_ADDR litmus:49999 litmus analysis server; empty disables it, falling back to hopper-only analysis
--uploads PRISM_UPLOADS off enable browser uploads via POST /upload
--public off public-deployment mode: atomdrift lab branding and Secure cookies
--no-cache off disable persistent caching (in-memory only)
--rate-limit 10 max requests per client IP per window before 429/challenge (0 disables)
--rate-window 10m window over which --rate-limit applies
PRISM_CSRF_KEY HMAC key for CSRF tokens (required for uploads)
CACHE_DIR OS user cache dir localfs cache location

Deployment

Production runs in a FreeBSD jail managed with bastille, using separate build and run jails:

make deploy # git pull + ./hacks/rollout-bastille.sh build prism

The rollout is effectively zero-downtime: the replacement binds the same port as the running process via SO_REUSEPORT_LB, the new process is health-checked on /_/health, and only then is the old one sent SIGTERM (it drains in-flight requests during a 5-second graceful shutdown). See hacks/rollout-bastille.sh for the full sequence and prerequisites (hopper-api / hopper-db entries in /etc/hosts, CF_TUNNEL_TOKEN).

make deploy is FreeBSD-only. The binary itself is portable — make build produces a static CGO_ENABLED=0 binary that runs anywhere Go does.

Development

make test # go test ./...
make integration # integration tests (live hopper, -tags integration)
make lint # shellcheck, golangci-lint, yamllint, biome

Hopper Query Discipline

Prism is a read-mostly cache layer in front of the hopper database. To survive traffic spikes without melting upstream, every read against hopper (DB query or hopper-api HTTP call) must flow through one of the fido.TieredCache wrappers declared in main.go. Fido's Fetch has built-in singleflight: N concurrent callers for the same key share one loader invocation.

Caches:

Cache Stored type What it wraps
cache storedResult per-SHA litmus analysis envelope
feedCache cachedFeedSnapshot every feed query (frontpage, criticality, ecosystem, domain, formula, free-text ?q=) — memory-only
reportCache cachedReport per-SHA AI reverse-engineering report
parentArchiveCache cachedParents per-SHA "found in N archives" list

If you need to add a hopper query, add (or reuse) a cache for it. Anti-patterns to refuse in code review:

  • Calling hopperDB.Foo(ctx, ...) directly from an HTTP handler.
  • Calling hopperClient.Do(req) outside a cache loader.
  • Using cache.Get + cache.Set instead of cache.Fetch (skips singleflight; two concurrent misses run two loaders).
  • Failing to cache the not-found result — wrap with a Found bool flag so SHAs without reports don't refetch every request.
  • Storing pre-formatted relative times ("5 minutes ago") in cached snapshots; cache the raw time.Time and re-derive at render.

Cache TTLs live in the const block at the top of main.go (feedCacheTTL, feedPrecacheInterval, auxCacheTTL). See doc.go for the package-level reminder.