Commit Graph
590 Commits
Author SHA1 Message Date
J3vbandClaude Fable 5 4b37c8024e fix(service): enforce attachment ownership atomically in the link UPDATE (W1-3)
The per-attachment GetAttachmentByID pre-check loop was a check-then-link
TOCTOU (the same race pattern this branch fixes elsewhere), an N+1 on the
hot send path, and a hard ErrForbidden for legit retries naming an
already-linked attachment. Ownership now lives in the one UPDATE that
links: `AND message_id IS NULL AND (uploader_id = ? OR uploader_id IS
NULL)` — a foreign attachment can never be claimed, legacy NULL-uploader
rows stay claimable, and skipped rows (foreign/linked/missing) are logged
but never fail the send, so retries can't hard-fail. Subsumes W2-4; the
MemStore (nil,nil) GetAttachmentByID contortion is replaced by a real
map-backed attachment store so the guard is testable (W3-5).

Companion commit updates test callsites and adds ownership coverage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 08:29:26 +02:00
J3vbandClaude Fable 5 a3f7d63f7d test(plugin): lock CPU-budget overrun recovery (W1-1)
Hand-assembled wasm fixture whose command_dispatch spins forever only for
payloads over 100 bytes: baseline dispatch succeeds, an over-budget dispatch
surfaces the budget error, and the next dispatch on the same plugin succeeds
again via lazy re-instantiation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 08:21:55 +02:00
J3vbandClaude Fable 5 b13adf23aa fix(plugin): re-instantiate wazero module after CPU-budget overrun (W1-1)
WithCloseOnContextDone(true) closes the module when the per-call budget
deadline fires, and nothing ever re-instantiated it — one over-budget
command bricked the plugin for every user until an admin disable/enable
cycle or a server restart. Now any guest-call failure that closed the
module (deadline, trap, parent-context cancellation) releases inst.module,
and the next dispatch lazily re-activates the same instance; a concurrent-
activation guard keeps double dispatches from leaking modules. Re-
instantiation resets guest in-memory state — documented at the budget site.

Host-call time exclusion from the budget is documented as a requirement but
not implemented: no host imports are wired into the runtime yet, so there
is no host-call time to exclude today.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 08:21:54 +02:00
J3vbandClaude Fable 5 0c093e8403 chore(server): delete unfinished Postgres scaffolding
PostgresStore was 86% stubs behind a build tag nothing enables, pgdbgen
carried hand-added build tags that fought sqlc-verify, and the runtime never
threaded store.Store through the handler boundary. Single-engine reality
shrinks the W1-3 attachment-ownership fix and ends the pgdbgen churn.
Removed: store/postgres.go, db/pgdbgen/, db/queries/postgres/,
migrations/postgres/, the sqlc postgres block, pgx from go.mod, the
startup-refusal branch, and the dead Postgres config surface.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 08:15:58 +02:00
J3vb d0da33f1da Merge remote-tracking branch 'origin/main' into fix/security-hardening-review 2026-07-19 08:09:56 +02:00
J3vbandClaude Fable 5 183ef09f7c chore(release): rotate server update signing key
New key ID 1D1E33AC50B11BC2 replaces ABB078FD8EBFF5FA, whose private half had
no recoverable backup. Rotation is free at this exact moment: the v1.0.0
fleet predates signature verification entirely and no verifying (alpha.1+)
install exists yet. Both SERVER_UPDATE_SIGNING_* secrets updated in lockstep;
private key + password backed up locally for the maintainer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 08:07:30 +02:00
J3vbandClaude Fable 5 01ec825e51 test(updater): lock tauri base64-wrapped signature round-trip
Covers the release pipeline's actual .sig format (base64-wrapped minisign),
the raw minisign format, garbage base64 rejection, and tamper rejection.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 08:07:30 +02:00
J3vbandClaude Fable 5 668e1bde83 fix(updater): accept tauri base64-wrapped minisign signatures
`tauri signer sign` emits .sig files that are base64-wrapped minisign
documents — the same wrapping already handled for the pinned public key —
but verifySignatureReader fed the wrapped text straight to
minisign.Signature.UnmarshalText, so every real release signature failed to
parse ("minisign: invalid signature"). Unwrap base64 when the text is not a
raw minisign document; raw documents (and the test fixtures) pass through
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 08:07:30 +02:00
J3vbandClaude Fable 5 25a2eae52f fix(release): repair server-asset signing and old-fleet update compatibility
Three latent bugs in the never-exercised publish path:

- `tauri signer sign -k` loads the key from a *string*; we passed the mktemp
  path, so the CLI base64-decoded "/tmp/tmp.XXXX" and died with "Invalid
  symbol 46, offset 8" (the dot). Use `-f` (key from file). The stored secret
  was never read and never at fault.
- checksums.sha256 lines carried "windows/"/"linux/" path prefixes; the
  v1.0.0 updater's ParseChecksumFile exact-matches the last field against
  "chatserver.exe", so every deployed 1.0.0 server would have failed the
  checksum lookup. Emit bare asset filenames (current updater accepts both).
- No end-to-end proof the signed assets verify against the pinned public key
  that ships inside the server binary. Add a fail-closed minisign verify step
  before any release is created; it catches key/pubkey mismatch, signature
  format drift, and signer flag regressions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-19 08:07:30 +02:00
J3vbandClaude Fable 5 9169dc99a1 chore(release): stamp client version 1.1.0-alpha.1
Forward-only versioning for the alpha reset: 1.1.0-alpha.N ascends
past the superseded v1.0.0 for every installed client, and the alpha
series stays below 1.1.0-beta.N and the final 1.1.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 15:37:01 +02:00
J3vb d2fa89dc1d Merge pull request #1181 from J3vb/reboot/p0-distribution
P0: decouple distribution from the source repo + alpha-reset hygiene
2026-07-18 15:36:30 +02:00
J3vbandClaude Fable 5 4bbfaa6a8d fix(ci): install xdg-utils for Linux AppImage bundling
The ubuntu-22.04-arm runner image does not preinstall xdg-utils, so
AppImage bundling fails with 'xdg-open binary not found'. Add it to
every Linux system-dependency list in ci.yml and release.yml (the
release ARM job shares the same list and would have failed identically
at tag time).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 15:11:26 +02:00
J3vbandClaude Fable 5 44bc996f70 fix(client): use valid bundle category SocialNetworking
'Network' is not a tauri-bundler AppCategory, so every bundling run
failed with 'invalid category' after compilation succeeded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 14:28:47 +02:00
J3vbandClaude Fable 5 35f225dca4 fix(client): resolve cargo audit findings
Bump crossbeam-epoch 0.9.20, quinn-proto 0.11.16, rustls-webpki
0.103.13 in Cargo.lock (semver-compatible; RUSTSEC-2026-0204, -0185,
-0098, -0099, -0104 and the second quick-xml instance resolved).

quick-xml 0.37 remains pinned by tauri-winrt-notification 0.7 (via
tauri-plugin-notification) with no compatible route to the fixed 0.41;
it only parses toast XML the library itself builds, never
attacker-controlled input, so RUSTSEC-2026-0194/-0195 are ignored in
.cargo/audit.toml with removal criteria documented inline.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 13:50:38 +02:00
J3vbandClaude Fable 5 20e9e2f6a5 fix(ws): don't clean voice state when a replacement connection exists
readPump teardown always ran handleVoiceLeave, trusting the joined_at
guard in LeaveVoiceChannelIfMatch to protect replacement sessions. On
reconnect the voice session TRANSFERS to the replacement client with
the same joined_at, so the guard cannot tell the two apart: whenever
teardown snapshotted voiceChID before the transfer zeroed it, the old
connection deleted the replacement's voice_state row (flaked on the
Windows CI runner as TestServeWS_Reconnect_PreservesVoiceState).

Gate voice cleanup on !replaced — the same condition the
presence-offline broadcast four lines down already uses. A genuinely
final disconnect behaves exactly as before, and a stale row from a
crashed replacement is still swept by the fresh-connect cleanup.

Also deflake TestHub_ConcurrentRegisterUnregister: poll for quiescence
with a deadline instead of a fixed 50ms sleep that loses to the -race
scheduler on slow runners.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 13:50:38 +02:00
J3vbandClaude Fable 5 2732b7c52d fix(client): clear clippy -D warnings findings in the Tauri shell
- cfg-gate open_devtools entirely behind the devtools feature (its
  registration in lib.rs already was), removing the dead-code warning
  in non-devtools builds
- drop let-bindings of unit-returning store.set in the three cert
  rollback paths (let_unit_value)
- remove a needless borrow on the startup-error dialog description
  (only compiled on non-Linux, hence Windows-only finding)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 13:21:05 +02:00
J3vbandClaude Fable 5 1fbedb404c fix(lint): delete dead ws broadcast cluster; demote phase-header comments
golangci-lint had been failing invisibly behind the earlier CI gate
failures. Default-build lint is now clean:

- Delete the unused pre-topic-limiter rate-limit constants, the unused
  bluemonday sanitizer, and the dead broadcast variants superseded by
  their Low/High counterparts (broadcastExclude,
  broadcastToDMParticipants(+Exclude), sendSequencedToUsers,
  PubSub.debugDump). Test references were comments only; updated to
  name the live variants.
- Separate 'Phase X Step Y' file headers from the package clause with a
  blank line so staticcheck ST1000 no longer reads them as malformed
  package comments (proper package docs exist in hub.go/manifest.go).
- Add .gitattributes normalizing line endings to LF on checkout —
  the Windows CI runner materialized CRLF, which made every
  prettier-formatted file fail the format gate.

Known remainder (pre-existing, out of P0 scope): golangci-lint with
-tags wazero reports 3 gosec + 2 staticcheck and -tags otel 1+1; CI
lints the default build. Tracked for the P1 plugin pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 12:55:22 +02:00
J3vbandClaude Fable 5 c5bd46d682 style(client): apply prettier across src and tests
Mechanical prettier --write; 297 files had drifted while the CI
format gate was dead. No functional changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 11:46:53 +02:00
J3vbandClaude Fable 5 2e6bce154e fix(ci): unblock the client pipeline; isolate the known-red test job
- Remove the unused 'type Event' named import from the committed
  generated events.ts and teach the CI patch step to strip it on future
  regenerations — the previous line-anchored patch deliberately skipped
  imports, so ESLint failed on every run.
- Split vitest into its own client-tests job so the known-red suite
  (P2 triage pending) is exactly one visible failing check instead of
  masking the audit/lint/typecheck/prettier gates, which are now green.
- Drop the three stale roadmap files (PHASE_BC_LOCAL_TODO.md,
  phase-b-acceleration.md, phase-c-differentiation.md) — referenced
  nowhere since the CHANGELOG cleanup; already deleted on the
  security-hardening branch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 11:46:52 +02:00
J3vbandClaude Fable 5 77ec4f1466 chore(db): commit stale sqlc output; make sqlc-verify honest
db/queries/sqlite/events.sql was changed (typed CAST for
GetMaxEventSeq) without re-running generation; commit the regenerated
dbgen (interface{} -> int64, no callers depend on the old signature).

Scope sqlc-verify's diff to db/dbgen: regeneration strips the
hand-added //go:build postgres tags in db/pgdbgen, so verifying that
tree can never pass; pgdbgen is scheduled for removal with the
Postgres scaffolding.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 11:45:30 +02:00
J3vbandClaude Fable 5 522003ebe3 fix(ws): wire topicLimiter into hand-rolled test hubs
newEmitTestHub and NewHubForTest built raw Hub literals without the
topic rate limiter, so deliverBroadcast panicked on a nil receiver and
TestEmitEvents_ChannelEvent_CallsBroadcastToChannel could never pass.
CI never surfaced it because the pipeline died at govulncheck first.
Wire the limiter exactly as NewHub does; no production nil-guard, since
a nil limiter in production would silently disable rate limiting.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 11:45:30 +02:00
J3vbandClaude Fable 5 c7b49ee1fc fix(deps): patch reachable vulnerabilities blocking CI
Server: golang.org/x/net 0.52.0->0.55.0 (GO-2026-5026, reachable via
autocert.HostWhitelist) and go-jose/v3 3.0.4->3.0.5 (GO-2026-4945,
reachable via the LiveKit SDK). govulncheck now passes clean; full
test suite and the otel/wazero build-tag matrix verified locally.

Client: npm audit fix (semver-compatible only, 44 packages) — npm audit
--audit-level=high now exits clean. vitest moved 3.2.4->3.2.7.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 11:45:30 +02:00
J3vbandClaude Fable 5 b4c34d2bc6 chore(repo): P0 hygiene for the alpha reset
- gitignore .serena/ and Client/tauri-client/.env; untrack the .env
  (the KLIPY key it held is treated as burned; rotation + server-side
  proxy tracked for P3)
- CI: verify generated sqlc output (make sqlc-verify) on the ubuntu leg
- CHANGELOG: honest reset narrative (v1.1.0-alpha series), remove
  references to deleted roadmap files
- delete stale docs/phase-a-status.md; fix dangling ref in
  docs/plans/slash-commands.md
- add root SECURITY.md (GitHub-surfaced policy; reporting works while
  the source repo is private)
- docs/audit-2026-04-07.md: add maintained finding-closure table

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 11:17:29 +02:00
J3vbandClaude Fable 5 e25018d6d2 feat(release): decouple distribution from the source repo
Publish every release to the public OwnCord-releases repo with a full
source snapshot (AGPL section 6 for binary recipients), and make the
updater's repo coordinates configurable (github.owner/github.repo),
defaulting to OwnCord-releases. Both the server self-update and the
/client-update chain follow the new default, so deployed servers keep
updating after the source repo goes private.

The publish step fails closed: a private source repo with no
RELEASES_REPO_TOKEN aborts the release instead of silently shipping
binaries with no public source or update feed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 11:17:29 +02:00
J3vbandClaude Opus 4.8 21816f52e7 docs(plans): remediation plan for security-hardening review regressions
Adds docs/plans/security-hardening-remediation.md capturing the code-review
findings against fix/security-hardening-review and sequencing the fixes into
three waves (availability/backend-breaking, behavioral regressions, cleanup).
Each item names root cause, right-altitude fix, files, and verification.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 21:55:24 +02:00
J3vb b084c07a17 Remove obsolete test files for agent-diff, agent-queue, backlog-parser, briefing-and-normalization, cache-mode, module-naming, and server-auth. These tests are no longer relevant to the current codebase and have been deleted to maintain a clean and efficient testing environment. 2026-07-17 21:11:17 +02:00
J3vbandClaude Opus 4.8 7b178ff30b fix(security): harden server against verified code-review findings
Applies fixes for 20 adversarially-verified findings from a whole-codebase
security review (server side). All Go build-tag variants build, `go vet` is
clean, and the suite passes (the sole failing test, ws TestEmitEvents, is a
pre-existing nil-harness failure unrelated to these changes).

High severity:
- auth: close TOCTOU in TOTP verify rate-limit by recording each attempt
  atomically up-front (was Check-then-Allow), restoring the per-user
  brute-force cap.
- plugin: enforce the CPU/time budget on every WASM guest call via a
  WithTimeout context (WithCloseOnContextDone interrupts runaways); the
  configured budget was previously parsed but never applied.
- api/waf: inspect request bodies for chunked (ContentLength==-1) requests
  so the SQLi/XSS/RCE body rules can no longer be bypassed.
- ws: rate-limit voice_join/voice_leave and voice_e2ee announce/offer, which
  fan out to every participant and could force mass disconnects.

Medium severity:
- api: run bcrypt on the unknown-user login path (no || short-circuit) to
  remove the timing-based username-enumeration oracle.
- ws: verify LiveKit webhooks via the SDK receiver so the signature is bound
  to the body hash (kills forgery/replay).
- authz: require READ_MESSAGES for reactions and for plugin-command
  broadcasts; route the latter through RequireChannelAccess.
- api: cache the client-update signature fetch and rate-limit the endpoint.
- service: propagate DeleteOtherSessions failure from ChangePassword instead
  of silently reporting success.
- api: trust the rightmost non-proxy X-Forwarded-For entry, not the
  client-controllable leftmost one.
- plugin: route auto-registered commands through the conflict-checked
  RegisterCommand; pin the DNS-validated IP for host_http dials
  (DNS-rebinding TOCTOU).
- api: mark access-controlled downloads private/no-cache + Vary: Origin.

Low severity:
- auth: fail closed when a fully-shaped TOTP ciphertext fails GCM auth
  (was returning the ciphertext as plaintext).
- api: apply the livekit-proxy path allowlist to WebSocket upgrades too.
- service: verify attachment ownership before linking (IDOR).
- admin: bound the bootstrap setup invite (5 uses / 24h); re-verify the
  update binary hash immediately before rename+spawn (TOCTOU).
- service: require BanMembers + role hierarchy for moderation ban/unban.

chore: stop tracking the stray Server/owncord-server.exe build artifact.

Test infra: add uploader_id to the hand-rolled ws test attachment schemas and
make MemStore.GetAttachmentByID a no-op lookup, matching production/DB behavior.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 21:08:54 +02:00
J3vb 34a84bcd5d Merge pull request #1132 from J3vb/claude/plan-phases-b-c-bGpoS
refactor: migrate WS handlers to V2 Command/Event architecture
2026-04-07 10:59:20 +02:00
Claude d680fe50f3 fix(client): remove deprecated tsconfig baseUrl
TypeScript reports TS5101 for `baseUrl`, which is deprecated and will
stop functioning in TS 7.0. The `paths` entries already use relative
`./src/*` patterns, so `baseUrl` is unnecessary and can be dropped
without changing module resolution.

https://claude.ai/code/session_01RrgSn7AUsGYVPRthnudVMr
2026-04-07 08:23:59 +00:00
J3vb eba2e3c715 fix(ci): anchor Event rename regex to line-start to avoid corrupting imports 2026-04-07 10:18:10 +02:00
J3vb 65002d0d7f h 2026-04-07 10:13:47 +02:00
J3vb ba66629077 fix(ci): resolve all golangci-lint and ESLint failures on PR #1132
Client:
- ci.yml: patch auto-generated events.ts to rename Event -> _Event
  so @typescript-eslint/no-unused-vars does not fail on generated code

Server (gocritic):
- service/channel.go: rangeValCopy (line 74), elseif (line 174)
- service/message.go: rangeValCopy (line 648), elseif (lines 438, 496)
- ws/emit.go: caseOrder — ChannelEvent before BroadcastAllEvent
- ws/handlers_command_test.go: stringXbytes — use bytes.Equal
- ws/pubsub_test.go: stringXbytes — use bytes.Equal

Server (nilerr):
- service/channel.go: nolint:nilerr for intentional silent drops in HandleTyping

Server (gosec):
- plugin/host_ui.go: G703 nolint — path already sanitized above
- plugin/registry.go: G302 — tighten plugin file permissions 0o640 → 0o600
- ws/hub.go, ws/serve.go: G115 nolint — seq counters never reach MaxInt64

Server (unused/unparam):
- plugin/registry.go: nolint:unused for wazero-tagged module field
- telemetry/metrics.go: nolint:unused for otel-tagged resetAppMetricsForInit
- ws/command.go: nolint:unparam for map entries whose error return is always nil

Server (staticcheck ST1000/ST1020):
- Add blank line before package declarations in phase-comment files
  (api/plugins_handler.go, plugin/host_{commands,events,http}.go,
   telemetry/metrics.go, telemetry/middleware.go,
   telemetry/telemetry_default.go, ws/event_persister.go)
- Fix GlobalTracer/GlobalMeter doc comments to start with function name
2026-04-07 10:10:38 +02:00
J3vb 64a6a8d4a4 Merge pull request #1149 from J3vb/claude/fix-eslint-issues-5ImcO
Migrate ESLint disable comments to Oxlint and format fixes
2026-04-07 09:49:20 +02:00
Claude 6608dd392f fix(client): correct prettier endOfLine and oxlint disable directives
The Client Typecheck & Test CI job was failing on the prettier format
check. Two real root causes, fixed properly:

1. prettier endOfLine was set to 'crlf' but the repo stores files with
   LF (no .gitattributes forcing eol), so 'prettier --check' failed on
   292 files on the Linux CI runner. Set endOfLine to 'lf' to match the
   on-disk reality. Also reformat the 2 files (pluginBridge.ts,
   solidAdapter.ts) that had genuine style issues.

2. 15 'eslint-disable-next-line' comments targeted oxlint-only rules
   (no-await-in-loop, no-unassigned-vars) that ESLint does not enable,
   so ESLint reported them as 'Unused eslint-disable directive'
   warnings. Switched the directive prefix to 'oxlint-disable-next-line'
   — oxlint still honors them (its native syntax), and ESLint no longer
   parses them as eslint directives, so the warnings are gone without
   suppressing the safety check or removing the directives that oxlint
   actually relies on.

Verified locally: oxlint, tsc --noEmit, eslint, prettier --check, and
npm audit --audit-level=high all exit 0.
2026-04-07 07:46:49 +00:00
J3vb 81c121c2bd fix(server): resolve golangci-lint contextcheck, errcheck, gocritic findings
contextcheck: add ctx context.Context as first param to ListVisibleChannels,
BlockUser, CreateDM, CreateInvite, UpdateProfile, SendMessage; pass r.Context()
from HTTP handlers and ctx from WS handler; replace context.Background() in
telemetry spans with the propagated ctx.

errcheck: suppress justified Close() errors — defer func(){ _ = rows.Close() }()
in sqlite_events.go (idiomatic; rows.Err() checked), _ = resp.Body.Close() in
host_http.go (body fully consumed), _ = f.Close() in host_ui.go (read-only fd).

gocritic/rangeValCopy: rewrite for _, ch := range all (line 60) to indexed loop
in ChannelService.ListVisibleChannels to avoid 144-byte per-iteration copy.
2026-04-07 09:10:14 +02:00
J3vb 16fbfcce87 fix(client): bump vite to patch high-severity CVEs (GHSA-4w7w-66w2-5vf9, GHSA-p9ff-h696-f583)
npm audit fix resolved vite <=6.4.1 → 6.4.2; 0 high/critical vulnerabilities remain.
2026-04-07 09:10:01 +02:00
J3vb f06ddcde27 Merge branch 'claude/plan-phases-b-c-bGpoS' of https://github.com/J3vb/OwnCord into claude/plan-phases-b-c-bGpoS 2026-04-07 08:26:25 +02:00
J3vb 081beddc45 Merge pull request #1148 from J3vb/claude/review-phase-completion-PBExk
Complete Phase B & C: OTel telemetry, Wazero plugins, and plugin admin API
2026-04-07 08:24:53 +02:00
Claude 1c476ccb58 merge: reconcile sister branch claude/plan-phases-b-c-bGpoS
Resolves the parallel Phase B/C work that landed on the sister branch
while this branch was in review. Both branches independently implemented
real OTel + Wazero runtimes; this merge keeps the best of each.

Conflict resolution
- Server/plugin/sandbox_wazero.go: rewritten as a hybrid. Keeps the
  HEAD lifecycle (eager `platformInit` with WASI preview-1, explicit
  `platformDeactivate` per-instance, runtime closed via Registry.Close)
  AND adopts the sister branch's richer artefacts:
    * `WithMemoryLimitPages` actually enforces `cfg.MaxMemoryMB`,
    * the JSON-over-linear-memory ABI
      (`allocate` / `command_dispatch(ptr,len) → (ptr,len)` /
      `deallocate`),
    * `listExportedCommands` auto-binds commands the plugin exports
      via `list_commands` at activation time (capability-gated).
- Server/plugin/registry.go: kept the HEAD `activate()` snapshot
  pattern (read `runtimePlatform` under RLock, pass into
  `activateWithRuntime` as a parameter) so a concurrent Close can't
  race the wazero call. Sister branch's LoadAll stale-staging cleanup
  and UninstallPlugin on-disk dir removal came in via auto-merge.
- Server/telemetry/telemetry_otel.go: kept the HEAD implementation
  (race-fixed AppMetrics rebind, uint64 overflow guard, idempotent
  shutdown, trace-provider cleanup on prom failure) and wired in the
  sister branch's `OTLPInsecure` config field for plaintext gRPC opt-in.
- Server/go.mod: accepted sister branch's `BurntSushi/toml v1.6.0`
  for the new TOML manifest support.
- Client/tauri-client/vitest.config.ts: union of both globs
  (`tests/**/*.test.ts`, `src/**/*.test.ts`, `src/**/*.test.tsx`).
- PHASE_BC_LOCAL_TODO.md: combined the two checkbox histories;
  TOML manifest, hello.wasm fixture, and OTLPInsecure are all marked
  done now.

Sister branch additions accepted via auto-merge
- Server/plugin/examples/hello/{hello.wasm,main.go}: precompiled 925
  KiB TinyGo plugin with the full ABI (allocate, deallocate,
  list_commands, command_dispatch, on_event).
- Server/plugin/manifest_{toml,nottoml}.go: TOML manifest parser
  behind the wazero build tag, JSON fallback elsewhere.
- Server/plugin/loader.go: prefers `plugin.toml`, falls back to
  `plugin.json`.
- Server/api/plugins_handler.go: structured error responses + slog.
- Server/main.go, Server/config/config.go: OTLPInsecure plumbing,
  defaults polish.
- docs/{contributing.md,server-configuration.md}: documentation
  updates.

Test status
- `go build` passes on default, -tags otel, -tags wazero, and
  -tags otel,wazero.
- `go vet` passes on every tag combination.
- `go test ./...` passes on default and on -tags otel,wazero.
- Client: `npx tsc --noEmit` clean; vitest 3188/3188 across 112 files.

https://claude.ai/code/session_01AZni6CDSQeu67WSWY1YCDX
2026-04-07 06:23:09 +00:00
J3vb 6a48665cb0 Merge branch 'claude/plan-phases-b-c-bGpoS' of https://github.com/J3vb/OwnCord into claude/plan-phases-b-c-bGpoS 2026-04-07 08:00:20 +02:00
J3vb 33607444b1 Merge pull request #1147 from J3vb/copilot/full-audit-changes
audit: fix 11 security and quality findings from Phase B+C PR review
2026-04-07 08:00:07 +02:00
J3vb 670e6e0323 security: harden plugin sandbox stdin and opaque internal errors
- sandbox_wazero.go: explicitly discard plugin stdin via WithStdin to
  prevent WASM modules from reading the server process's stdin fd
- channel_handler.go: replace ErrInternal message pass-through with
  generic 'an internal error occurred' — full error stays server-side
  in slog.Error only
- invite_handler_test.go: update assertions to expect generic message
2026-04-07 07:59:10 +02:00
copilot-swe-agent[bot]andJ3vb 1f4a89ced1 audit: fix all C/H/M/L severity findings from Phase B+C PR review
Agent-Logs-Url: https://github.com/J3vb/OwnCord/sessions/2d415fd9-6138-495b-ac29-c54d08ae4ce4

Co-authored-by: J3vb <192430104+J3vb@users.noreply.github.com>
2026-04-07 05:28:53 +00:00
copilot-swe-agent[bot] 813b67db61 Initial plan 2026-04-07 05:11:54 +00:00
copilot-swe-agent[bot]andJ3vb bd45b65dd3 Agent-Logs-Url: https://github.com/J3vb/OwnCord/sessions/6635420c-af26-4cc0-9397-5e5b37887437
Co-authored-by: J3vb <192430104+J3vb@users.noreply.github.com>
2026-04-06 22:06:23 +00:00
copilot-swe-agent[bot]andJ3vb 2dc9a060fc fix(review): address 6 reviewer findings from pullrequestreview-4064746778
- service/user.go: fix ChangePassword docstring (no old-password verification)
- service/user.go: RevokeSession now maps db.ErrNotFound→ErrNotFound and
  all other store errors→ErrInternal, preventing internal failures from
  masquerading as 404s
- plugin/loader.go: update scanPluginDirectory comment to reflect fail-fast
  behavior; fix Lstat comment wording
- db/queries/sqlite/events.sql: CAST COALESCE result to INTEGER so sqlc
  generates int64 instead of interface{}
- api/plugins_handler.go: log install error server-side and return sanitized
  structured JSON response instead of raw err.Error()
- .github/workflows/ci.yml: remove continue-on-error from tag build steps
  so tag boundary drift fails CI"

Agent-Logs-Url: https://github.com/J3vb/OwnCord/sessions/6635420c-af26-4cc0-9397-5e5b37887437

Co-authored-by: J3vb <192430104+J3vb@users.noreply.github.com>
2026-04-06 22:03:35 +00:00
Claude 47d848ee0a feat(phase-bc): implement real OTel + Wazero runtimes; harden install path
Phase B Step 8 (OpenTelemetry) and Phase C Step 9 (Wazero plugin runtime)
were structurally scaffolded but the tagged builds were placeholders that
errored at runtime. This commit lands the real implementations behind the
existing build tags, plus three review passes worth of fixes across the
plugin admin handler, plugin registry, telemetry adapter, and Solid client.

Telemetry (Phase B Step 8)
- Add real go.opentelemetry.io/otel{,/sdk,/exporters/{prometheus,otlp...}}
  modules to go.mod plus contrib/instrumentation/net/http/otelhttp.
- Replace the telemetry_otel.go skeleton with a working Provider that
  wires Prometheus + OTLP/gRPC exporters, otelhttp middleware, span and
  meter adapters, and an idempotent Shutdown.
- AppMetrics cache is now reset *before* SetGlobal to close a race where
  a concurrent NewAppMetrics() could observe a swapped provider but read
  stale no-op instruments.
- Init releases the trace provider on a later prometheus exporter
  failure so Init never leaks gRPC connections.
- convertAttrs handles int32/uint/uint32/uint64/float32 explicitly;
  uint64 values that exceed math.MaxInt64 fall back to a STRING attr
  rather than wrapping into a negative int64 and corrupting metrics.
- Tests under -tags otel cover the prometheus scrape, span lifecycle,
  histogram recording, shutdown idempotency, AppMetrics rebind, and
  the uint64 overflow fallback.

Plugin runtime (Phase C Step 9)
- Add github.com/tetratelabs/wazero v1.11.0 to go.mod.
- platformInit creates a shared wazero.Runtime with WASI preview1
  pre-instantiated; activateWithRuntime compiles + instantiates each
  plugin module under that runtime; platformDeactivate closes per-
  plugin modules without tearing down the runtime.
- DisablePlugin now calls platformDeactivate so the wazero module is
  freed immediately instead of leaking until registry Close.
- activate() captures runtimePlatform under r.mu.RLock and passes it as
  a parameter to activateWithRuntime; the call no longer re-reads the
  field, closing a race with concurrent Close.
- invokeCommand calls the plugin's command_dispatch export when
  present; missing/broken exports return a user-facing diagnostic
  instead of crashing the dispatcher.
- Tests under -tags wazero cover registry creation, module compilation,
  re-enable after disable (verifies the leak fix), close-twice safety,
  invalid wasm rejection, and DispatchCommand with a missing export.
  Fixture is a 41-byte embedded add.wasm; no external asset required.

Plugin admin handler hardening
- /api/v1/admin/plugins/install now rejects uploads whose multipart
  Content-Type is not application/zip|x-zip-compressed|octet-stream
  (415) and uploads whose body lacks the PK\\x03\\x04 / PK\\x05\\x06
  zip magic (400). The 16 MiB cap and registry-side zip-slip / symlink
  / size-bomb defences are still applied as before.
- New plugins_handler_test.go covers list-empty, install-503-when-nil,
  content-type rejection, magic rejection, happy path, lifecycle 503,
  invalid id, and isZipContentType / hasZipMagic helpers.

Solid client (Phase B Step 6) cleanup
- vitest.config.ts now wires vite-plugin-solid and broadens the test
  glob to include src/**/*.test.tsx so Badge.test.tsx is actually
  discovered (it was silently skipped).
- pluginBridge.ts targets postMessage at window.location.origin
  instead of "*", and exposes a destroy() that detaches the message
  listener and clears mounted frames.
- solidMount.ts imports the JSX type from "solid-js" instead of
  "solid-js/web" (the latter does not re-export it), unblocking
  npx tsc --noEmit.

Build/test status
- go build succeeds on default, -tags otel, -tags wazero, and
  -tags otel,wazero.
- go test passes on every tag combination across telemetry, plugin,
  api, ws, service, store, and the rest of the tree.
- Client: npx tsc --noEmit clean; vitest 3188/3188 across 112 files.

PHASE_BC_LOCAL_TODO.md is updated to mark the OTel modules + real Init,
the wazero module + real platformInit, and the test coverage that
landed in this commit as completed.

https://claude.ai/code/session_01AZni6CDSQeu67WSWY1YCDX
2026-04-06 21:46:22 +00:00
J3vb 86634c531e feat(phase-bc): add hello plugin WASM binary and source
- main.go: TinyGo WASI plugin implementing the OwnCord plugin ABI
  (allocate/deallocate, list_commands, command_dispatch, on_event)
- hello.wasm: precompiled binary (TinyGo 0.40.1, Go 1.25.3, wasm-opt 129)
  Responds to /hello [name] with a greeting; proof-of-life for wazero runtime
2026-04-06 23:40:03 +02:00
J3vb ae496082b3 feat(phase-bc): TOML plugin manifests + Solid vitest preset
Plugin TOML support (-tags wazero):
- manifest_toml.go: tryLoadPluginTOML using BurntSushi/toml v1.6.0
- manifest_nottoml.go: no-op stub for default build
- loader.go: prefers plugin.toml, falls back to plugin.json

Solid vitest preset:
- vitest.config.ts: add vite-plugin-solid, expand include to
  src/components/solid/**/*.test.tsx — Badge.test.tsx now runs
  automatically as part of npm test (112 files / 3188 tests)
2026-04-06 23:25:16 +02:00
J3vb ddaaadcd43 feat(phase-bc): implement OTel SDK wiring and wazero plugin runtime
OTel (telemetry/telemetry_otel.go, -tags otel):
- Real Init: prometheus pull-exporter + OTLP/gRPC push-exporter branches
- Bridge types: Tracer/Span/Meter/Counter/Histogram/Gauge wrapping SDK
- HTTP middleware via otelhttp (otelchi not in proxy; otelhttp is equivalent)
- Added otel v1.43.0, sdk, exporters/prometheus v0.65.0, otlptracegrpc,
  otelhttp v0.67.0, wazero v1.11.0 to go.mod

Wazero (plugin/sandbox_wazero.go, -tags wazero):
- ensureRuntimeLocked: lazy wazero.Runtime init with WASI host module
- activateWithRuntime: CompileModule + InstantiateModule per plugin
- invokeCommand: JSON-ABI dispatch via allocate/command_dispatch/deallocate
- listExportedCommands via list_commands export

Build matrix: default, otel, wazero, postgres, otel+wazero+postgres all pass
Server test suite: all packages green
2026-04-06 23:21:38 +02:00