Syncing model: architecture.jsonc 42 elements, 18 relationships, 3 views Forward sync: 2 elements created, 1 updated, 0 deleted; 3 connectors created, 0 updated, 0 deleted Reverse sync: 0 elements created, 1 updated, 0 deleted; 0 relationships created, 0 updated, 0 deleted Conflicts resolved: 0 (model wins)
Cross-cutting Concepts
8.1 Threat Model (STRIDE)
Bausteinsicht is a local CLI tool that reads and writes files on the user’s workstation. The primary trust boundary is the filesystem: the tool processes user-supplied JSONC and draw.io files and writes results back to the same directory.
STRIDE Threat Table
| ID | STRIDE Category | Severity | Threat | Mitigation |
|---|---|---|---|---|
T-1 |
Tampering |
Medium |
Malicious JSONC or draw.io file in the workspace overwrites model data via sync |
Atomic writes ( |
T-2 |
Tampering |
Low |
CLI flags |
Reject |
T-3 |
Information Disclosure |
Low |
|
File written at 0600; state contains no secrets, only structural metadata (SHA-256 checksums, element IDs) |
T-4 |
Denial of Service |
Low |
Oversized JSONC model file causes OOM or slow parse |
10 MB file size limit enforced before parsing (SEC-006) |
T-5 |
Denial of Service |
Low |
Deeply nested element hierarchy causes stack overflow during |
|
T-6 |
Tampering |
Low |
|
|
Spoofing and Repudiation are not applicable: the tool operates on local files under the user’s own identity; no authentication or audit log is required.
Risk Acceptance
Remaining accepted risks: * T-3 — sync state leaks structural metadata; acceptable because the file lives in the project directory alongside the model itself (same trust level). * Dockerfile script downloads without checksums (SEC-014) — deferred; upstream projects do not publish checksums.
See Security Review 2026-03-01 for the full SEC catalog.
8.2 Security Mitigations
Security controls implemented across the codebase, keyed to threat IDs:
| Control | Threat | Implementation |
|---|---|---|
Atomic file writes |
T-1 |
|
Path traversal guard |
T-2 |
|
Safe view key |
T-2 |
|
File permissions |
T-1/T-3 |
All model/sync files written at |
File size limit |
T-4 |
|
Element depth limit |
T-5 |
|
HTML sanitization |
T-6 |
|
Dependency scanning |
All |
|
|
Note
|
As of 2026-07-09, govulncheck, gitleaks (secret scanning), and go test -race run as
blocking CI jobs in .github/workflows/go.yml (govulncheck, gitleaks, test-race), all
verified clean against the current codebase (#550). gosec (SAST) and nilaway (nil-pointer
analysis) also run in CI but non-blocking (continue-on-error: true) for now: gosec currently
reports 35 pre-existing file-permission findings (tracked separately), and nilaway’s memory/time
footprint on a GitHub-hosted runner hasn’t been validated as reliably fast/light enough to gate every
PR on. `test-race excludes internal/importer/xmi — its ~118MB BigData.xmi test fixture makes
race instrumentation’s memory overhead impractical; the other 33 packages are raced normally. See
issue #550 for the follow-up to make
gosec/nilaway blocking once their respective backlogs are addressed.
|
8.3 Test Strategy
Decided in ADR-007. Three tiers:
| Tier | Volume | Scope | Characteristics |
|---|---|---|---|
Unit tests |
~70% |
Pure functions: label parsing, ID resolution, XML element creation, validation |
No I/O; <100 ms per test; co-located |
Integration tests |
~25% |
Package-level: full model load/save cycle, full XML round-trip |
|
E2E tests |
~5% |
Full CLI workflows: |
Execute compiled binary; real JSONC + draw.io files; <5 s per test |
Property-Based Testing
pgregory.net/rapid is used for roundtrip and idempotency properties:
-
Label escaping / unescaping roundtrip (
internal/drawio/) -
escapeHTML/trimBracketsinvariants
Test Fixtures
Packages use testdata/ directories for representative input files.
Golden-file comparisons are done by committing expected output and checking with bytes.Equal in tests.
There is no -update-golden flag; update expected files manually and recommit.
8.4 Observability
User-Facing Output
Normal output goes to stdout:
-
text (default) — human-readable summaries
-
json (
--format json) — machine-parseable; used by LLM agents
Warnings and errors go to stderr.
Verbose Mode
With --verbose, additional sync and export progress is printed to stderr (plain text, no [DEBUG] prefix):
Verbose output is suppressed in --format json mode to keep stdout machine-parseable.
No Logging Framework
Bausteinsicht uses fmt.Fprintf(stderr, …) for verbose output and fmt for normal output.
No external logging framework is used — log package is not imported in the CLI layer.
8.5 Error Handling
Strategy
Errors propagate upward and are only formatted for the user at the CLI layer (cmd/bausteinsicht/).
| Layer | Error Handling |
|---|---|
|
Return |
|
Catch errors, format them for the user (plain text or JSON), and set the exit code via |
Exit Codes
| Code | Meaning |
|---|---|
0 |
Success |
1 |
Validation error or sync conflict |
2 |
File not found or I/O error |
Structured Error Output
With --format json, errors are emitted to stderr as:
{"error": "validation failed: model.webshop.api unknown kind", "code": 1}
The single error string contains the full wrapped error chain. This enables LLM agents to parse errors programmatically.
|
Note
|
The details array (multiple per-field errors) is not part of the JSON error format. Validation warnings are only available in text mode via bausteinsicht validate.
|
8.6 JSONC Comment Preservation
Standard Go encoding/json does not support comments. Bausteinsicht strips comments before parsing and writes back selectively:
-
Remove single-line comments (
// …) and trailing commas before parsing -
Parse the cleaned JSON with
encoding/json -
On pure insertions (new elements, new relationships):
model.PatchInsert/cmd/bausteinsicht/sync.go:saveModelpatches only the changed lines, preserving existing comments and key ordering (ADR-011) -
On deletions or modifications of existing entries: full rewrite via
model.Save— comments are lost
|
Note
|
The REPL’s save command follows the same patch-first/full-save-fallback strategy.
|
8.7 File Atomicity
When writing files, Bausteinsicht uses a write-to-temp-then-rename pattern:
-
Write to a temporary file in the same directory (e.g.,
.model.jsonc.tmp) -
os.Renamethe temp file to the target path (atomic on most filesystems) -
On failure, the original file remains intact
This prevents corrupted files if the process is interrupted during write (mitigates T-1).
8.8 Configuration Discovery
Bausteinsicht uses convention over configuration:
-
Look for
*.jsoncin the current directory. Exactly one match is used as the model file; multiple files require--model(the tool never silently picks one, since it mutates synchronized files — SEC-005). -
Look for
*.drawioin the current directory (the diagram file) -
Look for
.bausteinsicht-syncin the current directory -
Template:
template.drawioin the current directory, or fall back to the embedded default
All paths can be overridden via CLI flags (--model, --template).
8.9 Version Management
The binary version is injected at build time via ldflags:
go build -ldflags "-X main.version=0.1.0" ./cmd/bausteinsicht
GoReleaser handles this automatically for tagged releases.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.