Commit Graph

161 Commits

Author SHA1 Message Date
sencho-quartermaster[bot] b6b154cb99 chore(main): release 0.67.1 (#885)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-05-02 16:51:35 -04:00
sencho-quartermaster[bot] d810a1bacc chore(main): release 0.67.0 (#871)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-05-02 13:27:44 -04:00
sencho-quartermaster[bot] 50e9a55c11 chore(main): release 0.66.2 (#868)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-05-02 00:59:42 -04:00
Anso 5e29649f3e chore: workflow hardening (husky+commitlint, dependency-review, stale, GHCR, mesh-sidecar digest) (#863)
* chore(repo): enforce Conventional Commits via husky and commitlint

release-please parses commit subjects on main to compute the next version
and regenerate CHANGELOG.md. A non-conforming commit silently breaks both,
so the format must be enforced at commit time, not by review.

Adds husky 9 to wire a commit-msg hook, commitlint with the conventional
config, and a small rule override (loosen subject length to 120 chars,
disable subject-case so existing imperative subjects keep passing). The
prepare script runs husky on npm install so contributors do not need to
configure it manually.

* ci: add dependency-review workflow

GitHub-native action that diffs the PR's manifests (package.json,
package-lock.json) against main and fails when a new transitive dep
introduces a high or critical CVE. Existing vulnerabilities tracked in
security/vex/sencho.openvex.json and the Trivy scan in ci.yml are not
re-flagged here.

Pinned to actions/dependency-review-action v4.9.0 by commit SHA. Comment
summaries are posted to the PR only on failure to keep the conversation
clean on green PRs.

* ci: add stale workflow for issues and pull requests

Marks issues and PRs as stale after 60 days of inactivity and closes 14
days later unless re-engaged. Issues labeled pinned, security, bug, or
tracking are exempt and never auto-closed; PRs labeled pinned or security
are exempt. Runs daily at 01:30 UTC and processes up to 30 items per run
to stay within the action's rate budget.

Pinned to actions/stale v10.2.0 by commit SHA.

* chore(repo): route new issues to docs, discussions, and security policy

Disables the blank-issue option and adds three contact links the issue
chooser surfaces above the bug-report and feature-request templates:
docs.sencho.io for setup questions, GitHub Discussions for open-ended
chat, and the repository security policy for private vulnerability
reports. This keeps the bug tracker focused on actionable bug reports
and feature requests instead of support questions.

* ci(docker): publish multi-arch image to GHCR alongside Docker Hub

Mirrors every released sencho and sencho-mesh image to ghcr.io with the
same tags, signing, and supply-chain attestations as the Docker Hub copy.
Same content; pull from whichever registry your environment prefers.

- Adds packages:write to both publish jobs so the auto-provisioned
  GITHUB_TOKEN can push to ghcr.io/studio-saelix/sencho and -mesh.
- Adds a second docker/login-action step authenticating to ghcr.io. The
  Docker Hub login still resolves credentials from the production env.
- docker/metadata-action now lists both image references; one buildx push
  attaches the manifest to both registries in a single round trip.
- Cosign keyless signing already loops over $TAGS, so adding the GHCR
  reference is enough to sign both digests.
- The cosign attest step now loops over both registry paths so SBOM (CDX
  + SPDX) and OpenVEX attestations are resolvable from either registry.

Quickstart and image-verification docs note GHCR as an alternative pull
source with identical content.

* fix(mesh-sidecar): pin base image by digest

The main Sencho Dockerfile pins every base image by sha256 digest so a
republish of an upstream tag cannot silently shift content into a
release. The mesh-sidecar Dockerfile pinned node:22-alpine by tag, which
is exactly the gap that pinning closes.

Resolves node:22-alpine to its current multi-arch index digest (covers
linux/amd64 and linux/arm64) and threads it through both build stages
via a single ARG so a future digest roll only edits one line. The inline
comment documents the resolution command.

The sidecar holds an outbound websocket and has no inbound HTTP
listener, so adding a HEALTHCHECK is intentionally out of scope: a
process-liveness probe would be tautological with Docker's restart
policy. The Dockerfile now records that decision so it does not get
reopened on every audit.

* ci(docker): use repository_owner for GHCR login username

github.actor varies by event source (the maintainer who merged the
release PR on tag pushes, github-actions[bot] on bot-driven runs, the
dispatcher on workflow_dispatch). The username field is metadata only;
GITHUB_TOKEN is what authenticates against GHCR. github.repository_owner
resolves to a fixed value (studio-saelix) on every event and matches
GitHub's own example workflows for GHCR push.

* chore(repo): tighten commit subject-case rule

Disabling subject-case entirely allowed accidental ALL-CAPS or
PascalCase subjects through. Restrict to "never upper-case or
pascal-case" instead, which preserves the lowercase / kebab-case
norm of this repo and lets sentence-case subjects (used sparingly
on main) keep passing.
2026-05-02 00:49:49 -04:00
sencho-quartermaster[bot] 344d24698e chore(main): release 0.66.1 (#864)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-05-01 21:17:16 -04:00
sencho-quartermaster[bot] 593d916696 chore(main): release 0.66.0 (#853)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-05-01 19:59:34 -04:00
SaelixCode 2c85bc7219 Merge branch 'main' of https://github.com/AnsoCode/Sencho
# Conflicts:
#	package.json
2026-04-29 09:28:43 -04:00
SaelixCode 3da0aa6036 chore: migrate repository URLs from AnsoCode/Sencho to studio-saelix/sencho
Updates all hardcoded GitHub repository references across 21 files:
- package.json: repository URL, bugs URL, homepage, description, author
- CONTRIBUTING.md: bug report template URL
- SECURITY.md: advisory URL, cosign cert-identity regexp
- .github/CODEOWNERS: @AnsoCode -> @studio-saelix/maintainers
- .github/workflows/ci.yml: repositories scope (Sencho -> sencho), docs-sync git URL
- .github/workflows/cla.yml: path-to-document URL
- .github/workflows/docker-publish.yml: cosign verify comment
- frontend/**/*.tsx: issues and changelog links (3 components)
- frontend/public/.well-known/security.txt: Contact and Policy URLs
- security/vex/sencho.openvex.json: @id field
- docs/openapi.yaml: license URL
- docs/docs.json: navbar and footer GitHub links (5 instances)
- docs/security.mdx: advisory and SECURITY.md links
- docs/reference/verifying-images.mdx: repo link + cosign regexp + legacy identity note
- docs/reference/contact.mdx: issues, LICENSE, advisory, policy, CoC links
- docs/reference/security-advisories.mdx: releases link
- docs/operations/verifying-images.mdx: cosign regexps and VEX download URL (6 instances)
- docs/operations/upgrade.mdx: releases links (2 instances)
- backend/src/utils/version-check.ts: GitHub Releases API endpoint

CHANGELOG.md intentionally excluded (release-please managed).
Legacy cosign identity note added for pre-migration image verification.
2026-04-29 09:24:20 -04:00
sencho-quartermaster[bot] bc2b0a9725 chore(main): release 0.65.1 (#840)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-29 01:53:27 -04:00
sencho-quartermaster[bot] fe53c7e3e5 chore(main): release 0.65.0 (#812)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-28 10:31:39 -04:00
sencho-quartermaster[bot] 79753c6a37 chore(main): release 0.64.2 (#806)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-27 11:04:33 -04:00
sencho-quartermaster[bot] de50a2fab2 chore(main): release 0.64.1 (#804)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-27 09:12:47 -04:00
sencho-quartermaster[bot] d592bdd724 chore(main): release 0.64.0 (#728)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-27 00:55:02 -04:00
dependabot[bot] fdab44fe07 chore(deps-dev): bump otplib from 12.0.1 to 13.4.0 in the all-npm-root group (#723)
* chore(deps-dev): bump otplib in the all-npm-root group

Bumps the all-npm-root group with 1 update: [otplib](https://github.com/yeojz/otplib/tree/HEAD/packages/otplib).


Updates `otplib` from 12.0.1 to 13.4.0
- [Release notes](https://github.com/yeojz/otplib/releases)
- [Commits](https://github.com/yeojz/otplib/commits/v13.4.0/packages/otplib)

---
updated-dependencies:
- dependency-name: otplib
  dependency-version: 13.4.0
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: all-npm-root
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(e2e): migrate otplib imports to v13 API

The v13 release removed the singleton authenticator export. Switch to
the OTP class with generateSync, passing per-call options.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: SaelixCode <dev@saelix.com>
2026-04-26 16:34:01 -04:00
sencho-quartermaster[bot] 81abd73fc7 chore(main): release 0.63.0 (#700)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-21 08:52:41 -04:00
sencho-quartermaster[bot] 75d93d20db chore(main): release 0.62.0 (#686)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-19 15:04:43 -04:00
sencho-quartermaster[bot] 47eaffdf93 chore(main): release 0.61.0 (#675)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-18 18:54:42 -04:00
sencho-quartermaster[bot] 4c79093abd chore(main): release 0.60.0 (#672)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-17 22:58:20 -04:00
sencho-quartermaster[bot] bc91c754c8 chore(main): release 0.59.0 (#668)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-17 22:06:16 -04:00
sencho-quartermaster[bot] 7d390bd54d chore(main): release 0.58.1 (#660)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-17 14:43:14 -04:00
sencho-quartermaster[bot] d2c6c26fe8 chore(main): release 0.58.0 (#655)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-17 13:40:17 -04:00
sencho-quartermaster[bot] 5ec9d50b41 chore(main): release 0.57.0 (#647)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-17 08:18:25 -04:00
sencho-quartermaster[bot] 3d112969cf chore(main): release 0.56.0 (#644)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-16 21:33:51 -04:00
sencho-quartermaster[bot] baf3123efa chore(main): release 0.55.1 (#641)
Co-authored-by: sencho-quartermaster[bot] <275163604+sencho-quartermaster[bot]@users.noreply.github.com>
2026-04-16 20:34:43 -04:00
sencho-token-app[bot] 8190274247 chore(main): release 0.55.0 (#636)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-16 15:04:37 -04:00
sencho-token-app[bot] 8c767e3925 chore(main): release 0.54.1 (#631)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-16 08:17:04 -04:00
sencho-token-app[bot] da5471d7ac chore(main): release 0.54.0 (#627)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-15 23:16:29 -04:00
sencho-token-app[bot] 6d084540bd chore(main): release 0.53.0 (#624)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-15 20:53:17 -04:00
sencho-token-app[bot] 7bda33d780 chore(main): release 0.52.0 (#621)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-15 19:52:51 -04:00
sencho-token-app[bot] ecdfd77453 chore(main): release 0.51.0 (#616)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-15 18:46:53 -04:00
Anso 7d78c9fe22 feat(auth): add TOTP two-factor authentication with backup codes (#615)
* feat(auth): add TOTP two-factor authentication with backup codes

Adds RFC 6238 time-based one-time password support to every tier,
integrated with the existing password and SSO login paths.

Backend:
- New MfaService wrapping otplib with a plus or minus 1 step tolerance,
  base32 secret generation, and hashed single-use backup codes (bcrypt).
- user_mfa and mfa_used_tokens tables in DatabaseService. The second
  table is a DB-backed replay blacklist, purged on a 60s interval.
- authMiddleware now recognizes an mfa_pending scope. A token carrying
  that scope is rejected on every route except the MFA challenge and
  logout, so no API surface is reachable before the second factor
  clears.
- /api/auth/login issues only a short-lived mfa_pending cookie when the
  user has MFA enrolled. /api/auth/login/mfa consumes that cookie,
  verifies the code (or backup code), and swaps in a real session.
- /api/auth/mfa/* routes for status, enrol/start, enrol/confirm,
  disable, backup-code regenerate, and SSO-bypass opt-in.
- Admin recovery path: POST /api/users/:id/mfa/reset clears the target's
  MFA state, bumps token_version, and writes an audit log entry.
- CLI emergency fallback: backend/src/cli/resetMfa.ts is wired via
  `npm run reset-mfa <username>` and also exported for tests.
- SSO flows (LDAP and OIDC) gate on user_mfa.sso_enforce_mfa before
  issuing a session; default behaviour keeps the SSO path frictionless.
- Per-user lockout after 5 consecutive failed codes (15 min).

Frontend:
- AppStatus gains an mfa-challenge branch driven by /api/auth/status.
- New MfaChallenge screen, MfaEnrollDialog (QR plus manual secret plus
  backup codes), MfaDisableDialog, MfaBackupCodesDialog.
- Account section shows a Two-factor authentication card with enrol,
  regenerate, disable, and the SSO-enforce toggle (shown only when SSO
  providers are configured).
- Users section gains a Reset 2FA action for admins.

Docs:
- New user guide at features/two-factor-authentication.mdx.
- New admin guide at operations/two-factor-admin.mdx.
- SSO page cross-links to the 2FA doc.

* fix(mfa): drop unused TEST_PASSWORD import and stale eslint disable

* fix(mfa): simplify e2e openAccountSettings helper to match working pattern

* fix(mfa): make e2e suite self-contained and always clean up

Test #2 called loginAs() before the MFA challenge step, which waited for
the dashboard indicator that never appears once the previous test enrolled
the user. That timeout skipped the rest of the serial block, including
the disable step, leaving MFA enabled and breaking every later spec.

Two fixes:

- Tests #2 and #3 now navigate directly to the login page instead of
  piggybacking on loginAs, which only handles the password-only path.
- A new afterAll hook unconditionally disables MFA via the API using two
  unused backup codes, so the DB is reset even if a test fails midway.

* fix(e2e): use backup code for mfa recovery to avoid totp replay race

The final recovery step in the backup-code replay test previously
generated a fresh TOTP to sign back in. When the timing landed inside
the same 30-second window that test #2 consumed, the server's replay
blacklist correctly rejected it, producing a ~50% flake rate. Backup
codes are single-use and sidestep the replay window, so the recovery
becomes deterministic.

* fix(e2e): drive mfa disable test through the challenge screen

Test #4 called loginAs after test #3 left MFA enabled, but loginAs
waits for the dashboard indicator and does not handle the challenge
screen, so it timed out. Drive the login manually, satisfy the
challenge with a backup code, and use a backup code for the disable
step too to avoid any TOTP replay-window race against earlier tests
in the serial block.
2026-04-15 18:45:51 -04:00
sencho-token-app[bot] 215a3a8f99 chore(main): release 0.50.0 (#610)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-15 11:35:03 -04:00
sencho-token-app[bot] 3da17905ba chore(main): release 0.49.0 (#607)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-15 08:06:18 -04:00
sencho-token-app[bot] 3dbfb6604e chore(main): release 0.48.1 (#604)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 22:33:28 -04:00
sencho-token-app[bot] 9ea8dcf44c chore(main): release 0.48.0 (#601)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 21:13:59 -04:00
sencho-token-app[bot] 5f82796a2a chore(main): release 0.47.0 (#598)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 18:21:21 -04:00
sencho-token-app[bot] 64f9d4f3e8 chore(main): release 0.46.20 (#595)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 16:42:56 -04:00
sencho-token-app[bot] baafc955eb chore(main): release 0.46.19 (#592)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 14:38:14 -04:00
sencho-token-app[bot] 7615a6068d chore(main): release 0.46.18 (#589)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 13:52:57 -04:00
sencho-token-app[bot] 6ffac2a0db chore(main): release 0.46.17 (#587)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 11:58:48 -04:00
sencho-token-app[bot] 819ca8a213 chore(main): release 0.46.16 (#584)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 11:05:09 -04:00
sencho-token-app[bot] bf0e8e14ed chore(main): release 0.46.15 (#581)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 10:12:29 -04:00
sencho-token-app[bot] 816a69034d chore(main): release 0.46.14 (#578)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-14 08:32:08 -04:00
sencho-token-app[bot] 0324578827 chore(main): release 0.46.13 (#574)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 22:17:54 -04:00
sencho-token-app[bot] eaa4ab7841 chore(main): release 0.46.12 (#571)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 21:42:03 -04:00
sencho-token-app[bot] b541b1168c chore(main): release 0.46.11 (#568)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 18:56:20 -04:00
sencho-token-app[bot] 1d9fdd9f25 chore(main): release 0.46.10 (#565)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 17:49:03 -04:00
sencho-token-app[bot] 98225d540f chore(main): release 0.46.9 (#562)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 15:50:56 -04:00
sencho-token-app[bot] 1a8ce3a3c9 chore(main): release 0.46.8 (#559)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 14:34:41 -04:00
sencho-token-app[bot] c703e196a4 chore(main): release 0.46.7 (#556)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 13:28:00 -04:00