When a branch/HEAD fetch fails (network error, auth failure, server down),
_open_remote now logs a warning rather than silently passing. A boolean
is_stale propagates through _get_repo → fetch_ifc so callers know the data
comes from a stale local cache.
The service adds X-Ifcurl-Cache: stale to /preview and /render_diff responses
when stale data was served, so Forgejo or a browser viewer can surface a
warning to the user.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All ifcopenshell calls (from_string, filter_elements, geom.iterator) now
run inside a short-lived child process via run_sandboxed(). A SIGSEGV or
SIGABRT in the child returns HTTP 422 instead of killing the service worker.
Configurable timeout (IFCURL_SANDBOX_TIMEOUT, default 120s) and optional
resource limits (IFCURL_SANDBOX_MEMORY_MB, IFCURL_SANDBOX_CPU_SECS).
The T3 GUID cache still works: the sandboxed pipeline returns resolved
GUIDs on selector miss so the parent can populate the cache; on hit the
parent passes cached GUIDs and the child converts them to step IDs.
Tests use a sync_sandbox fixture that runs run_sandboxed synchronously so
mock patches remain visible; four dedicated sandbox tests cover normal
return, exception propagation, segfault detection, and timeout.
Closes ifcurl-vm5.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GET /preview now accepts a token= query parameter, matching POST /preview
- Forgejo Go: add SERVICE_TOKEN config field; renderer appends it to <img src>
preview URLs so a machine-user token can authenticate private repos
- Go tests: verify token appears in preview URL when set, absent when unset
- viewer.html: BCF import via drag-and-drop or Import .bcf button in BCF row;
parses first viewpoint camera/clips/GUIDs and reloads with the viewpoint
applied to the current model context
- viewer-url.js, viewer.html: unescape %24 → $ in URL building so GlobalIds
with $ characters are human-readable in ifc:// URLs
- README: document SERVICE_TOKEN and private-repo preview configuration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SSRF: test local transport rejection, allowlist enforcement, private/loopback/
link-local IP blocking, allowlist with port, public host permitted without list
- GET /preview: happy path, invalid scheme, local transport rejection
- Tier 2 LRU: eviction at capacity, LRU promotion, cache miss
- git: heads/<branch> ref form (was only tested via HEAD/tag/hash)
- clear_caches fixture now also resets _allowed_hosts between tests
103 → 118 passing tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ifcurl/auth.py: token config (~/.config/ifcurl/tokens.json),
get_token_for_host(), inject_token() for HTTPS URL credential injection
- ifcurl/git.py: thread token= through fetch_ifc/fetch_ifc_bytes/_open_remote;
authenticated fetch uses 'git fetch <auth_url> +refs/*:refs/*' so the
token is never written to on-disk git config
- ifcurl/service.py: optional token field in PreviewRequest; request token
takes precedence over config-file token; get_token_for_host imported at
module level for clean monkeypatching in tests
- tests
Generated with the assistance of an AI coding tool.