The home emitted /objectStorageAdmin/<table> (or /<parent>/objectStorageAdmin/
<table>), which Next does not serve. Links now use /app/<table>, configurable
through ObjectStorageQBitConfig.tablePathPrefix (default /app), matching the
other qbits.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
QRun-IO/.github#2 adds a tag-and-release job that signs vX with the
QRUN_TAG_SIGNING_KEY secret after Maven Central confirms the artifact.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SessionCredentialsClient is gone: the session token now rides core
S3BackendMetaData.sessionToken, and the presigner takes its credentials from
core S3ClientFactory.buildCredentialsProvider. SecretRefs keeps only the
qbit's allow-list; ${file.PATH} resolution is core QMetaDataVariableInterpreter
(read-only, allowed roots /var/run/secrets and /run/secrets by default).
Tests point qqq.fileReference.roots at their temp dirs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shared (cleared on every node): bucket-row presign limits and enabled
header rules, invalidated by the new ConfigRowChangeCustomizer on the
bucket and header-rule tables, and capability statuses, invalidated per
key when a probe result is recorded (other nodes reload from the row).
The 15 s TTLs stay as the safety net. Row-id maps, S3 clients, process
permissions, provider defaults, the running-scan guard and the per-pod
presign rate limiter are node-local, with reasons.
Builds against QQQ 4.1.0-SNAPSHOT (qqq.snapshot.version) until the QQQ
RC with ClusterCaches is published; a release must pin that RC.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The producer read a literal version, so released artifacts reported a stale
or -SNAPSHOT version. qbit-object-storage.properties (version=${project.version}) is
Maven-filtered and the producer loads it; tests assert producer == bundle ==
artifact version.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On release branches the bundle's version and the producer's differed, so the
bundle test that asserts they match failed, and released bundles recorded
SNAPSHOT as their provenance. help/*.yaml is now filtered:
version: ${project.version}.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Host-neutral help (deployment-specific facts removed), registered with
HelpBundles, gated by HelpBundleAssertions. QQQ 4.1.0-RC.7.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The FK changesets from #20 are PL/pgSQL DO blocks; H2 cannot run them, which broke
#21's DefaultsChangelogTest. FKs stay real on Postgres (PostgresIndexTest covers them).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- effective limit is min(code, row); row 0/null/higher is ignored; config never mutated
- applied to presignGet/Put/Post, previewUrl and the download-link action; row read cached 15 s
- Setup card takes connections and buckets from the runtime config and counts rules as system
- seed changeset rollback is empty; test that a host rule survives rollback
- host help kept test, stand-in marker prose in the bundle
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Help bundle for all 12 tables and the app (ObjectStorageHelp), Setup card on
the home, disabled default-mutable header rule via a jar changelog tested
through real Liquibase on H2, tables guardrail test. The bucket row's presign
limits are now read at runtime (ConfigSync.withBucketOverrides). The version
table is documented as reserved and not used yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ObjectStorageSchema now declares a foreign key for each join and table
possible value (fk_<table>_<column>): capabilities, folders, objects,
versions, references and usage cascade from their bucket or object;
object.folder_id and object_reference.object_id are set null; a bucket's
connection, its header and protection rules and the operation log
restrict. Each key is added by an idempotent DO block that first records
orphans in qqq_fk_quarantine and clears (nullable) or deletes (required)
them, so the same statements upgrade an existing schema. Three new
indexes back keys that had none.
PostgresIndexTest gains the guardrail (every relation has a database
foreign key with its rule, every key column leads an index), the
upgrade path with orphans run twice, and the delete paths the scan uses.
Builds on #19 (feature/object-id-indexes).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The folder -> objects, object -> versions and object -> references child
lists filter on the parent id alone, but every existing index on those
tables leads with bucket_id. The generated schema now adds
ix_object_storage_object_7 (folder_id), ix_object_storage_object_version_2
(object_id) and ix_object_storage_object_reference_3 (object_id). They are
appended, so existing generated index names keep their numbers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Db.asSystem built an anonymous QSession subclass with every permission
but no token. Token-based authentication modules (OAuth2, Auth0) accept a
QSystemUserSession without a token and reject any other tokenless session,
so on such hosts every system read and write failed in session validation
(JWTDecodeException: The token is null). ConfigSync never mirrored the
code-defined connections and buckets, and the operation log, object index,
capabilities and protection/header rule scoping silently did nothing.
Use core QSystemUserSession(instance), which carries the same permissions
and all-access keys.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Moves qqq-orb@0.6.8 to qqq-orb@0.6.9, which passes --update-snapshots so cached SNAPSHOT dependencies are re-checked on every build (QRun-IO/qqq-orb#22).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move the core baseline to the released 4.1.0-RC.6 (architecture review
finding F19, guardrail G7). Adopt qbit-build-parent 2.1.0 with the
architecture guardrails enforced (G1, G3, G4, G7) and tests in strict
raw-route mode (G2). Everything passes with no source changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Expose a bucket's upload limit in the api package (null means no limit),
so consumers such as qbit-collaboration need not read the internal
StorageBucketConfig through config(). Found by the qbit-guardrails G1-arch
check (qbit-bom#10).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>