vee1e

vee1e / 828e8ff65b06fc44691ec5bf28ec5d4f

Last active 1 hour ago

Like 0
quantumstrand-migration.md Raw

QUANTUMSTRAND → FLOSS Integration Guide

Status: living plan (exploration POC in progress)
Base branch: quantumstrand (now up to date with master)
Exploration branch: refactor/first-class-modular (fork for modular layout; 2–3 iterations expected)


0. Locked product constraints (2026-07 mentor sync)

These supersede earlier GSoC “backward compatible / opt-in flag” assumptions.

Topic Decision
Compatibility No legacy JSON/API compatibility required — this is a major FLOSS release
Feature flag --quantum is not the end state. Prefer QS-style output as the default where applicable; flag only OK briefly during exploration
Naming Prefer domain names (layout, tags, enrich) over long-lived qs/ package branding. CLI experiment names can die with the major release
Binary One floss binary only — no parallel quantumstrand / qs release artifact
GUI Out of scope — do not migrate qs-viewer / Pages
Dependencies Always install layout/tag deps (lancelot, pyelftools, machofile, msgspec, …) as core
LFS All tag DBs + FLIRT .sig files on Git LFS
Tags on string kinds Apply text tags to static + stack + tight + decoded + language strings
Logging Global timestamps (%Y-%m-%d %H:%M:%S prefix) as on QS logging_.py
PR shape Smaller reviewable PRs along the way (not one unreviewable mega-dump). Exploration may be 1 branch; land as stacked/small PRs
Iterations ~2–3 exploration rounds expected (“POC → keep what we like / rewrite if needed”) — not endless
Master sync master already merged into quantumstrand (deps/CI); work forks from QS

What this means technically

  • FLOSS ResultDocument may break old consumers; design the right schema once.
  • Do not invest in dual-format adapters or long-lived qs_* optional fields “for safety” unless they still read well as first-class names (e.g. tags, section, structure, layout).
  • Prefer one pipeline: deobfuscation (FLOSS) + layout/tag context (QS) → one document → one renderer.

1. Executive summary

QUANTUMSTRAND is a mature experiment on quantumstrand: layout-aware static strings, tag databases, OSS rebuild CI, LFS, tests. It still lives under floss/qs/ as a second product (qs entry point + separate JSON).

Remaining work is productization, not greenfield features:

  1. Make layout + tagging first-class FLOSS modules (no floss/qs/ ghetto).
  2. Split monoliths (qs/main.py ~2.5k lines, floss/main.py ~850 lines).
  3. Unify CLI/output for a major release.
  4. Keep OSS DB pipeline healthy and reviewable (see §4).

Not remaining work (already on QS branch): PE/ELF/Mach-O layout, tag loaders, LFS, OSS build script + CI, most unit tests.


2. Branch / process model

master ──┐
         ├── already merged ──► quantumstrand (integration base)
                                    ├── refactor/first-class-modular  (POC #1)
                                    ├── … possible POC #2–3 …
                                    └── stacked small PRs → master (major release)
Practice Guidance
Base Fork exploration off quantumstrand, not stale master
POC Allowed to be messy; throw away or cherry-pick what works
Landing Prefer small PRs (layout move, tags move, CLI wire, CI paths…) for review
Rounds Budget 2–3 exploration iterations, not open-ended rewrite loops
Mega-PR Avoid one PR that is both “all features” and “all renames” without history; stack if needed

3. Current inventory (quantumstrand)

3.1 Still true

Area Location Notes
Layout + tags + Rich UI + QS CLI floss/qs/main.py (~2585 lines) Monolith to split
Tag DBs floss/qs/db/ + data/ (LFS) Move to floss/tags/
OSS builder scripts/build_oss_db.py Keep; fix paths after move
OSS CI .github/workflows/build-oss-db.yml Bi-weekly + dispatch
FLOSS CLI / deobfuscation floss/main.py (~843) Split parser vs pipeline
Viewer qs-viewer/ Do not migrate
Parallel build build-qs.yml, qs.spec Drop for release

3.2 OSS library builds (fork status)

Successful library build work tracked on the fork:

Expect updated DBs + workflow fixes to land on QS; migration paths must follow whatever tree those PRs use.

3.3 Build-time profile (vcpkg matrix, ranked)

Longest library builds observed (profiled run). Use this to prioritize CI time, timeouts, and optional continue-on-error / shard strategy — not as a reason to block migration.

Rank Library Duration Seconds
1 libmysql 00:32:55 1975
2 libarchive 00:10:24 624
3 libxml2 00:05:09 309
4 poco 00:04:06 246
5 boost-graph 00:03:40 220
6 libsndfile 00:03:31 211
7 capnproto 00:02:44 164
8 libev 00:02:27 147
9 avro-c 00:02:20 140
10 boost-log 00:02:18 138
11 libgit2 00:02:18 138
12 sail 00:02:09 129
13 libevent 00:01:48 108
14 czmq 00:01:29 89
15 sdl2 00:01:28 88
16 boost-test 00:01:19 79
17 libsrt 00:01:16 76
18 libhv 00:01:14 74
19 boost-filesystem 00:01:04 64
20 boost-chrono 00:01:04 64

Takeaways:

  • libmysql alone ~33 minutes dominates wall time; consider excluding from default weekly matrix, building on a slower cadence, or isolating in its own job.
  • Top ~5 libraries are most of the cost; document matrix exclusions explicitly in libraries.json / workflow comments.
  • CI caching of vcpkg may help but native builds will remain expensive.

4. OSS DB PR reviewability (new requirement)

Problem: updating .jsonl.gz LFS blobs makes GitHub diffs opaque (“binary files differ”).

Requirement: when OSS DBs change, emit a text summary of string-level changes for humans.

Proposed behavior (build_oss_db.py + workflow)

  1. After rebuild/merge per library, compute a textual diff vs previous DB:
    • added / removed / changed string keys (and maybe library_version).
  2. Write artifact e.g. floss/tags/data/oss/build_diff.txt (or upload CI artifact).
  3. PR body (create-pull-request action) includes a truncated summary:
    • ~100 lines max of the text diff (head + “… N more lines” footer).
  4. Full diff remains as workflow artifact for download.

Example PR body fragment:

## OSS DB update summary (truncated)

### openssl.jsonl.gz
+ 12 strings
- 3 strings
~ 1 version stamp change on existing keys

```diff
+ "OpenSSL 3.x..."
- "OpenSSL 3.0.7..."
...

(… truncated; see build_diff.txt artifact …)


This is independent of the modular refactor but should land with the OSS pipeline PRs.

---

## 5. Target architecture (first-class, no `qs/` package)

### 5.1 Package layout

```text
floss/
  main.py              # thin CLI entry only
  cli.py               # argparse / StringType
  pipeline.py          # full analysis orchestration
  results.py           # major-release schema (layout + tags + deobfuscated strings)
  ranges.py            # Range, Slice, OffsetRanges
  enrich.py            # apply layout mapping + taggers to result strings
  logging_.py          # timestamps
  strings.py / utils.py / stackstrings.py / tightstrings.py / string_decoder.py
  identify.py / language/ / features/ / sigs/

  layout/              # binary structure (from qs/main compute_*)
    __init__.py        # compute_layout()
    base.py            # Layout ABC, section/segment nodes, Structure
    pe.py / elf.py / macho.py
    extract.py         # strings in layout gaps

  tags/                # classification DBs (from qs/db)
    __init__.py        # load_taggers(), apply
    rules.py           # mute/hide/highlight, FP lib filter
    expert.py / gp.py / oss.py / winapi.py
    data/              # LFS (crt, expert, gp, oss, winapi)

  render/
    default.py         # primary human output (context-aware)
    json.py
    layout_text.py     # Rich section tree helpers if still needed

scripts/
  build_oss_db.py
  tags/                # VT/GP helpers moved out of package

Deleted for release direction: floss/qs/, qs console script, build-qs.yml, qs.spec, qs-viewer/ (unmigrated).

5.2 Pipeline (major release mental model)

sample
  → static / language strings
  → layout.compute_layout (PE/ELF/Mach-O)
  → tags on all string kinds
  → section/structure on offset-bearing strings
  → vivisect deobfuscation (stack/tight/decoded) when enabled
  → tags on recovered strings
  → single ResultDocument → render

No dual “FLOSS mode vs QS mode” long term.

5.3 Schema naming (preference under major bump)

Because compatibility is not required, prefer plain names over permanent qs_ prefixes:

Concept Prefer Avoid long-term
tags on a string tags qs_tags
section name section qs_section
structure name structure qs_structure
layout tree layout qs_layout
feature enabled meta omit or version only qs_enabled

POC may still use temporary names; final major release should look like FLOSS, not like an experiment bolted on.

5.4 Split map (qs/main.py → modules)

Region Destination
Range, Slice, OffsetRanges floss/ranges.py
ExtractedString + ascii/unicode extractors used by layout floss/layout/extract.py (or share floss/strings.py later)
Layout hierarchy + Structure floss/layout/base.py
PE / ELF / Mach-O compute floss/layout/{pe,elf,macho}.py
compute_layout floss/layout/__init__.py
DB query + load_databases floss/tags/__init__.py
hide/mute/FP rules floss/tags/rules.py
Rich render floss/render/layout_text.py
Pydantic QS ResultDocument fold into floss/results.py or floss/document.py during unify
QS main() delete → floss.main / pipeline

5.5 Split map (floss/main.py)

Region Destination
make_parser, enums, ArgumentParser floss/cli.py
viv load / sigs / file type floss/workspace.py (optional)
analysis body floss/pipeline.py
entry floss/main.py

6. Exploration plan (2–3 iterations)

Iteration 1 — Modular POC (this branch)

  • Physically remove floss/qs/ ghetto: layout/, tags/, ranges.py, render split.
  • Keep behavior: existing QS tests green under new imports.
  • Optionally thin-shim nothing on final tip (no floss.qs imports).
  • Do not require perfect unified schema yet.

Iteration 2 — Unified pipeline / schema

  • One ResultDocument including deobfuscated strings + tags + layout.
  • Default output is context-rich (no --quantum).
  • Drop parallel entry points and unused release workflows.

Iteration 3 — Polish

  • OSS text diffs in PR bodies.
  • CI matrix tuning using build-time profile (libmysql etc.).
  • Docs + release notes for major bump.
  • Delete dead code / experiment naming.

Each iteration should yield reviewable PR(s), not only a private branch.


7. File / CI checklist (release direction)

Move / add

  • floss/ranges.py, floss/layout/**, floss/tags/**, floss/enrich.py, floss/cli.py, floss/pipeline.py
  • LFS attributes for floss/tags/data/** and floss/sigs/*.sig
  • Core deps in pyproject.toml (no optional [qs] long-term)
  • build-oss-db.yml paths + text diff in PR body
  • Tests renamed/imported from floss.layout / floss.tags

Do not land

  • qs-viewer/, web-release.yml (GUI)
  • build-qs.yml, qs.spec, qs script (parallel product)
  • Long-term dual JSON compatibility layers

Preserve from master (already on QS)

  • verify-pins.yml, AGENTS.md, modern dep pins

8. Testing gates

pytest                       # full
pytest -k "layout or tags or qs or enrich or main"   # during rename churn
# smoke
floss sample.exe
floss sample.exe -j

Corpus still needed later: disk PE vs memory dump, ELF stripped, fat Mach-O (section parsing edge cases from GSoC notes remain valid).


9. Open questions (narrowed)

Question Status
Backward compatible JSON? No (major release)
Permanent --quantum? No — default QS-style output
Keep floss/qs/ name? No long-term
GUI? No for now
How many rewrite rounds? ~2–3
One mega-PR? Prefer small PRs; exploration branch OK
DB PR visibility? Yes — truncated text diff in PR body
Final field names tags vs qs_tags? Prefer plain tags under major bump; confirm in Iteration 2

10. Document history

Date Notes
2026-07-09 Initial inventory vs master; GSoC slices; early open decisions
2026-07-09 Locked: feature flag, core deps, single binary, no GUI, LFS, tag all string kinds, log timestamps
2026-07-10 §21 modular first-class layout proposal
2026-07-11 Mentor sync: no back-compat; QS output default; small PRs; 2–3 iterations; master∈QS; OSS PR #13/#14; library build profile; opaque DB diff → text summary; exploration branch process

Update this file when POC outcomes change the preferred schema or module map.


11. POC iteration 1 status (refactor/first-class-modular)

Date: 2026-07-11

Done

  • Removed floss/qs/ package entirely.
  • First-class modules:
    • floss/ranges.py
    • floss/layout/ (pe, elf, macho, base, extract, checks, util)
    • floss/tags/ (+ LFS data under tags/data/)
    • floss/document.py (layout-aware result document)
    • floss/analyze_static.py (CLI for layout+tags static analysis)
    • floss/render/layout_text.py
    • floss/cli.py (parser extracted from main.py)
    • floss/enrich.py (stub for iteration 2 unify)
  • Core deps promoted in pyproject.toml (no [qs] extra / no qs script).
  • Dropped build-qs.yml + qs.spec.
  • OSS workflow paths → floss/tags/data/oss.
  • Tests updated to new imports.

Tests

250 passed, 2 skipped, 6 xfailed

(full pytest tests/ on this branch)

Not done yet (iteration 2+)

  • Unify deobfuscation pipeline with layout/tags (single default output, no dual docs).
  • Extract remaining main.py body into pipeline.py.
  • Textual OSS DB diffs in PR bodies.
  • Plain field names (tags/section/layout) for major release schema.
  • PyInstaller floss.spec datas for tags/data (currently only FLOSS sigs).
  • Landing as small stacked PRs onto master.