Commit Graph
75 Commits
Author SHA1 Message Date
mrhid6 91d10a7650 fix: send the bare address as SMTP envelope sender so mailcow DKIM-signs v0.3.3 2026-09-11 11:00:40 +00:00
mrhid6 91841174dd fix: send email parts as quoted-printable so they are 7-bit clean and DKIM-signed v0.3.2 2026-09-11 09:57:40 +00:00
mrhid6 fbc9d4b9c4 fix: restore email says billing continues the paid period v0.3.1 2026-09-11 09:20:15 +00:00
mrhid6 50ab63ff13 feat: account dispute emails v0.3.0 2026-09-10 13:21:04 +00:00
mrhid6 5c87505820 feat: instance lock and purge fields for HQ disputes 2026-09-10 13:17:33 +00:00
mrhid6 e1ad2467d2 feat: Updated email templates v0.2.2 2026-09-10 12:06:29 +00:00
mrhid6 059949674d chore: replace em dashes with hyphens, add no-em-dash rule to CLAUDE.md 2026-09-10 09:18:58 +00:00
mrhid6 759d36e85d feat: add the mcp licence feature constant v0.2.1 2026-09-08 13:27:54 +00:00
mrhid6 02a6502f12 docs: add CLAUDE.md covering the module and its mirrored contracts v0.2.0 2026-09-08 08:43:44 +00:00
mrhid6 66eed23f79 chore: bring proto/ in with its history 2026-09-08 08:43:17 +00:00
mrhid6 2dd4d8acda fix: declare grpc dependency in shared go.mod
The workspace supplied it; a standalone build of the module could not
resolve google.golang.org/grpc at all.
v0.1.0
2026-09-08 07:36:13 +00:00
mrhid6 15f1231ecf refactor: rename shared module to gitea.hostxtra.co.uk/vantage/vantage-shared 2026-09-08 07:34:53 +00:00
mrhid6 fac195e6f9 feat: Move grpc pbs to shared 2026-09-07 15:50:25 +00:00
mrhid6 797135c506 fix: validate manifest collection names and route archive accessors through safeJoin 2026-09-07 14:45:37 +00:00
mrhid6 7df71ed8d4 fix: correct verify's ciphertext field map against the models 2026-09-07 14:45:36 +00:00
mrhid6 590a85fe3a fix: replay index specs verbatim instead of reconstructing them 2026-09-07 14:45:36 +00:00
mrhid6 01844ef285 feat: Add backup verify with a live decrypt probe
A fingerprint comparison proves two archives agree about a key. Only
opening real ciphertext from the target proves the key in hand reads the
data, which is the question an operator actually has.
2026-09-07 11:26:34 +00:00
mrhid6 5b7648577e feat: Add the backup restore
Every refusal happens before the first write: format, checksums, key
policy, then target inspection. A unique index that will not build aborts,
because the unique indexes here are tenant-isolation properties rather
than optimisations.
2026-09-07 11:23:27 +00:00
mrhid6 3f66370b1f feat: Add the backup dump
Collections are enumerated live rather than from a list, so a collection
added later is backed up with no code change. Documents are written as the
raw BSON the driver returned, so Decimal128, ObjectId, DateTime and binary
subtypes survive byte for byte.
2026-09-07 11:16:38 +00:00
mrhid6 525dc6af00 feat: Add the backup archive writer and reader
Open extracts and verifies every member against the manifest before the
reader is usable, so a corrupt archive is refused before a restore writes
its first document rather than halfway through.
2026-09-07 11:10:17 +00:00
mrhid6 07c68b170b feat: Add the backup archive manifest
KeyFingerprint is a pointer so an archive that recorded no key is a state
restore can report, not a default it silently treats as a match.
2026-09-07 11:08:02 +00:00
mrhid6 088ebe9848 feat: Add key fingerprinting for backup archives
Fingerprint hashes the raw key bytes rather than the hex string, so the
same key written in different cases fingerprints identically.
2026-09-07 11:03:48 +00:00
mrhid6 296bafd9e8 feat: Extract AES-GCM into shared/cryptobox
services/crypto.go keeps its function names and its KEY_ENCRYPTION_KEY
lookup and delegates the cipher, so vantagectl's verify probe can decrypt
with the same implementation rather than a second copy.
2026-09-07 10:55:54 +00:00
mrhid6 85d4c40ccb feat: status page schema, licence feature and indexes 2026-08-24 14:00:00 +00:00
mrhid6 abd28f2e17 feat: Report whether a managed host is waiting on a reboot 2026-08-13 10:39:27 +00:00
mrhid6 72ed02d83b feat: Add a per-instance API token lifetime cap
A pointer with absent meaning no cap, so an upgrade allows never-expire
tokens exactly as before and an instance opts into the policy. It governs
issuance only: changing it never invalidates a token that already exists.
2026-08-12 14:22:12 +00:00
mrhid6 3320c87659 fix: Harden instance rename against interleaving and lost unwinds 2026-08-12 11:08:36 +00:00
mrhid6 f75b2024e0 feat: Add instance rename to shared provisioning 2026-08-12 10:01:56 +00:00
mrhid6 2e87d4c10d feat: Changes to self hosted purchase 2026-08-11 09:30:19 +01:00
mrhid6 26f00c2f7f feat: store workload reports and route log results 2026-08-07 08:56:26 +01:00
mrhid6 b004143ea7 feat: workload registry proto messages 2026-08-07 08:53:33 +01:00
mrhid6 6e8f384782 feat: vuln_scanning entitlement and documentation
Adds license.FeatureVulnScanning as the one name for the feature and a
catalogue row per deployment/tier, following console and oidc: features
are opt-in per customer, so no plan bundles it.

Documents the subsystem in CLAUDE.md, including that ScopedCollections is
the canonical registry instance deletion derives from — there is no
separate deletion list, which the plan had wrong.
2026-08-06 14:44:11 +01:00
mrhid6 18c2982acc feat: vulnerability scanning pipeline, matcher, scheduler and API
Completes tasks 10-15 and fixes what was outstanding:

- vulndb.Pull implemented with oras-go, streaming the ~50MB layer and
  staging both files before replacing either, so a failed pull leaves the
  previous database intact rather than a half-written one.
- db.go: Vulnerability.Severity is a string, not trivy Severity, so the
  int conversion did not compile. Severity now resolves vendor (highest
  when vendors disagree) then NVD then unknown, and CVSS is read too.
- findings.go: added sweepFixedFindings plus the fleet query, severity
  counts, rescan flag and accept/unaccept the API needs.
- vulnrules.go: added rule CRUD and the digest builder. ResolveTargets
  returns []models.Server, not []string, so filterByServers was wrong.
- api/vulnerabilities.go was an empty file while handlers.go registered
  twelve routes against it; written, grouped by CVE.
- shared/mail: added the missing sender. The templates were orphaned and
  the HTML one was a copy of the text one, defining "subject" (which
  html/template would escape) and emitting no markup. render.go parses
  every template in init(), so a bad one panics server, admin and sitesvc
  at boot — go build never runs init(), which is why nothing complained.
- notify: digests dispatch through their own path so SMTP gets the digest
  template rather than arriving dressed as a monitor alert.
2026-08-06 14:33:46 +01:00
mrhid6 f29b75e325 feat: ReportPackages wire types with hash short-circuit
The pb packages are hand-written, not protoc-generated, and the wire
codec is JSON (encoding.RegisterCodec(JSONCodec{})). Field numbers in
the .proto are documentation; JSON field names are the contract. Both pb
packages edited by hand to match.

SyncResponse.collect_packages is omitempty and absent decodes as false,
so an older server leaves agents collecting nothing rather than
collecting without a licence.
2026-08-06 13:17:44 +01:00
mrhid6 fad7621d42 feat: Removed email alert settings 2026-08-03 14:40:15 +01:00
mrhid6 9d6c530b5c feat: add local_login_enabled setting with absent-means-on default 2026-08-03 10:36:48 +01:00
mrhid6 b8b553c695 feat: Removed unused test units 2026-08-03 10:18:01 +01:00
mrhid6 58bd26030c feat: Added ping command 2026-07-31 17:10:59 +01:00
mrhid6 131570da01 feat: add ProxyStream wire types for agent-relayed console 2026-07-29 12:37:37 +01:00
mrhid6 ece5384739 chore: updated deps 2026-07-28 15:07:19 +01:00
mrhid6 4b53970de3 feat: Updated package path to match repo 2026-07-28 10:01:40 +01:00
mrhid6 3c54ac92e9 feat: Updated package path to match repo 2026-07-28 10:01:40 +01:00
mrhid6 dc0d6cb2d2 feat: Move mail system to shared 2026-07-28 09:50:46 +01:00
mrhid6 03cf1715b2 feat: Updated purchase page 2026-07-27 14:59:43 +01:00
mrhid6andClaude Opus 5 ae503c2d3b feat(license): two deployments times three tiers, and two new limits
Plans are keyed on (deployment, tier) rather than tier alone, which is what
ends Free being cloud-only by construction - there is a self-hosted Free
plan now, so the one-per-account rule has to be enforced per deployment
instead of falling out of the plan table.

tier self_hosted becomes a legacy value no new licence carries.
NormaliseTier maps it to self-hosted Professional, which is what it always
granted, so blobs we cannot re-sign keep working.

Limits.FillUnset exists because a licence signed before a field existed
decodes it as 0, and 0 would read as no monitors and an audit log trimmed
to nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 23:41:43 +01:00
mrhid6andClaude Opus 5 df603c7219 fix(admin): licence and plan features serialise as [], never null
Free has no features, so a nil Go slice served "features": null. The
portal's type said string[], called .length on it, and took the page down.

The guarantee lives on a named Features type with its own MarshalJSON
rather than at each of the six places a licence or plan is serialised,
because the seventh is the one that would have been forgotten. Applying it
at marshal time also fixes rows already holding null in Mongo, which a
write-side fix alone would not.

Same class, found while checking the rest: staffListInstances built its
expiring filter from a nil []string, marshalling to $in: null, which Mongo
rejects — so the quiet week when nothing is expiring is precisely when the
staff Operations page's own query would have failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 18:10:07 +01:00
mrhid6andClaude Opus 5 ec5808be25 feat(shared): auth_source constants and hq_user_id on User
Nothing writes them yet. They land now so phases 2 and 3 do not require a
second rebuild of every service that consumes the shared module.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 12:52:15 +01:00
mrhid6andClaude Opus 5 af5043c353 feat(shared): unique users index is (instance_id, email)
One address is one user within an instance, not globally, so an account's
people can be projected into every instance they are granted.

The replacement index is created before email_1 is dropped, so a failure
at any point leaves a working constraint. The drop is idempotent and
tolerates two services racing it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 12:48:27 +01:00
mrhid6andClaude Opus 5 a0ebe85a31 chore: declare go 1.26 rather than 1.26.4 across the workspace
The 1.26.4 floor meant a base toolchain of 1.26.2 could not load the
workspace at all: the terminal worked only because GOTOOLCHAIN=auto
silently swapped in a downloaded 1.26.4, and gopls -- which does not get
that switch -- failed every packages.Load with

  go: go.work requires go >= 1.26.4 (running go 1.26.2)

Nothing needed the patch-level floor. agent/go.mod already declared plain
go 1.26, so this makes the workspace uniform rather than introducing a new
convention, and CI is unaffected because golang:1.26 is already newer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 19:33:58 +01:00
mrhid6 d7ada3eb76 fix(server): add the lk go.sum entry the workspace was masking
go build inside the Docker image runs outside the workspace, so server/go.sum
needed the hyperboloide/lk entry that GOWORK resolution was supplying locally.
Caught by the image build, not by go build.
2026-07-24 15:35:01 +01:00