Commit Graph

300 Commits

Author SHA1 Message Date
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
sencho-token-app[bot] 4c6c1c7481 chore(main): release 0.46.6 (#553)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 12:50:17 -04:00
sencho-token-app[bot] 0df877c6e6 chore(main): release 0.46.5 (#550)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 11:39:10 -04:00
sencho-token-app[bot] 0cfd43cb80 chore(main): release 0.46.4 (#546)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-13 10:04:31 -04:00
sencho-token-app[bot] 4eed8cde85 chore(main): release 0.46.3 (#543)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 22:08:21 -04:00
sencho-token-app[bot] 6002a5b630 chore(main): release 0.46.2 (#540)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 21:25:59 -04:00
sencho-token-app[bot] b494edaf7d chore(main): release 0.46.1 (#537)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 20:30:59 -04:00
sencho-token-app[bot] b76029e05d chore(main): release 0.46.0 (#534)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 19:58:39 -04:00
sencho-token-app[bot] 2c2d76d241 chore(main): release 0.45.6 (#531)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 19:31:04 -04:00
sencho-token-app[bot] 04bac48c68 chore(main): release 0.45.5 (#528)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 15:35:23 -04:00
sencho-token-app[bot] fd31b87598 chore(main): release 0.45.4 (#524)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 14:32:14 -04:00
sencho-token-app[bot] 9aadfcebed chore(main): release 0.45.3 (#521)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 05:46:21 -04:00
sencho-token-app[bot] c02f8a5de0 chore(main): release 0.45.2 (#518)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 04:27:01 -04:00
sencho-token-app[bot] 98a712657a chore(main): release 0.45.1 (#515)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 03:20:27 -04:00
sencho-token-app[bot] c18f5258e5 chore(main): release 0.45.0 (#511)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 02:27:38 -04:00
sencho-token-app[bot] 51b53b3088 chore(main): release 0.44.1 (#510)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 02:24:11 -04:00
sencho-token-app[bot] 6af1029894 chore(main): release 0.44.0 (#507)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-12 01:15:36 -04:00
Anso 4aa49f371d docs: clean and sanitize CHANGELOG history (#505)
Audit cleanup of CHANGELOG.md accumulated over 43 releases:

- Delete 23 orphaned `[Unreleased]` sections. Release-please does not
  consolidate manually-added Unreleased content into the next release, so
  each previous contributor's notes were left stranded between release
  blocks. The auto-generated release sections above each orphan already
  captured the commits.
- Sanitize internal implementation details that should not be in a
  public changelog: internal service/class/middleware names, library
  names, container file paths, internal endpoint paths, exact rate-limit
  thresholds, encryption primitives, and CVE/version-specific remediation
  details.
- Normalize tier naming throughout: legacy "Team Pro" / "Personal Pro" /
  "Sencho Pro" / "(Pro)" references rewritten to "Skipper" / "Admiral" /
  "Skipper and Admiral" per current product tiering.
- Deduplicate the v0.39.0 bulk dump and other sections where
  release-please swept the same commit subjects in multiple times.
- Rewrite the v0.1.0 section from a raw engineering log (with file
  paths, attack payloads, and internal module names) into user-facing
  release notes organised by Security / Added / Fixed / Changed /
  Removed.
- Update CONTRIBUTING.md to tell contributors not to edit CHANGELOG.md
  directly, matching the actual release-please flow. This is the root
  cause that created the 23 orphan Unreleased sections in the first
  place.

Verification:
- `## [Unreleased]` count: 0
- Legacy tier name count: 0
- Internal service/library name count: 0
- CVE IDs: 0
- File shrunk from 1,599 to 901 lines
2026-04-10 23:26:48 -04:00
sencho-token-app[bot] 3be5adcb4a chore(main): release 0.43.4 (#502)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-10 21:37:44 -04:00
Anso 9eb945a6f0 fix: run as root by default to eliminate stack-folder permission failures (#501)
Every filesystem operation against user compose folders (save, create,
deploy, update, rollback, template install, fleet snapshot restore)
previously failed with EACCES whenever a stack container had chowned
its own bind mount to another UID, which is extremely common with
linuxserver/* images and anything that runs as root by default.

Running Sencho as root eliminates the entire class of permission bugs
at the source and matches the default posture of Portainer, Dockge,
Komodo, and Yacht. Mounting /var/run/docker.sock is already equivalent
to root-on-host, so the previous non-root hardening provided essentially
no additional isolation while breaking real features.

Changes:

- docker-entrypoint.sh: default path stays root, no GID dance, no
  privilege drop. Opt-out via SENCHO_USER=sencho restores the legacy
  behavior bit-for-bit (chown data dir, match Docker socket GID,
  su-exec to the user). Fails fast if SENCHO_USER names a nonexistent
  account. Kubernetes / OpenShift forced-non-root compat preserved via
  the existing id -u = 0 guard.
- FileSystemService: delete forceDeleteViaDocker (the ~40-line helper
  that shelled out to an alpine container to work around EACCES during
  deleteStack) and simplify deleteStack to a single fsPromises.rm call.
  Tests updated accordingly.
- Dockerfile: keep the sencho user+group pre-created so the opt-out
  path works out of the box; comments updated to document the new
  default.
- Docs: new "Container user" section in configuration.mdx documenting
  the root default and the SENCHO_USER opt-out; troubleshooting and
  self-hosting updated to match.
2026-04-10 21:35:31 -04:00
sencho-token-app[bot] 8c54d8d5cc chore(main): release 0.43.3 (#499)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-10 20:42:18 -04:00
Anso ba9c4f4aa6 fix(compose): move atomic backup out of stack folder, silence stale stats 404s (#498)
The Skipper/Admiral atomic deploy/update path used to create
.sencho-backup/ inside the user's stack folder, which silently failed
with EACCES whenever a container had chowned the bind mount (swag,
tautulli, linuxserver/* images, etc). That broke auto-rollback and the
manual rollback endpoint for those stacks. Stack backups now live under
<DATA_DIR>/backups/<stackName>/ next to sencho.db, which is always
writable by the Sencho user.

While stress-testing the same scenario, MonitorService also flooded the
error log with "Error parsing stats for container ... 404 no such
container" because per-container stats polls (30s tick) raced with
docker compose recreating containers. The 404 case is now skipped
silently; non-404 stats failures still log at error level.
2026-04-10 20:06:17 -04:00
sencho-token-app[bot] f09da9ed69 chore(main): release 0.43.2 (#496)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-10 17:39:47 -04:00
Anso 4003e7c047 fix(fleet): capture local self-update helper errors (#495)
The helper container that runs `docker compose up --force-recreate` was
spawned with `docker run -d`, so the command returned immediately with
just the container ID. Any failure happening INSIDE the helper (bad
compose file, image mismatch, permission issue, socket problem) was
invisible: execFile's callback only fired for `docker run` command
errors, never for errors inside the detached helper. The UI fell back to
the generic 3-minute "Local update did not complete" heuristic with no
actionable information.

The helper now runs attached, so execFile's callback receives the
helper's exit code and stderr directly for any failure that happens
before the recreate kills this process. Additionally, the helper
persists exit code + stderr to `/app/data/.sencho-update-error` before
exiting, so the error survives the gateway's own death. On startup,
`SelfUpdateService.recoverPreviousError()` reads and deletes that file,
routing the real error through the existing `getLastError()` path so the
freshly booted gateway reports exactly why the previous attempt failed
instead of the generic timeout.
2026-04-10 17:39:01 -04:00
sencho-token-app[bot] d909e1995a chore(main): release 0.43.1 (#493)
Co-authored-by: sencho-token-app[bot] <275163604+sencho-token-app[bot]@users.noreply.github.com>
2026-04-10 16:37:21 -04:00
Anso 12fe79fc85 fix(deps): migrate SSO OIDC code to openid-client v6 (#492)
* chore(deps): bump the all-npm-backend group across 1 directory with 4 updates

Bumps the all-npm-backend group with 4 updates in the /backend directory: [@aws-sdk/client-ecr](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-ecr), [openid-client](https://github.com/panva/openid-client), [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) and [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest).


Updates `@aws-sdk/client-ecr` from 3.1026.0 to 3.1028.0
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-ecr/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.1028.0/clients/client-ecr)

Updates `openid-client` from 5.7.1 to 6.8.2
- [Release notes](https://github.com/panva/openid-client/releases)
- [Changelog](https://github.com/panva/openid-client/blob/main/CHANGELOG.md)
- [Commits](https://github.com/panva/openid-client/compare/v5.7.1...v6.8.2)

Updates `@types/node` from 25.5.2 to 25.6.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `vitest` from 4.1.3 to 4.1.4
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.4/packages/vitest)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-ecr"
  dependency-version: 3.1028.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: all-npm-backend
- dependency-name: openid-client
  dependency-version: 6.8.2
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: all-npm-backend
- dependency-name: "@types/node"
  dependency-version: 25.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: all-npm-backend
- dependency-name: vitest
  dependency-version: 4.1.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: all-npm-backend
...

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

* fix(deps): migrate SSO OIDC code to openid-client v6

The v5 Issuer/Client/generators API was removed upstream. Rewrite the
OIDC auth flow in SSOService to use the v6 functional API:

* discovery()/Configuration replace Issuer.discover + new issuer.Client
* buildAuthorizationUrl replaces client.authorizationUrl
* authorizationCodeGrant replaces client.callback, and handles the
  state check internally so the manual CSRF guard is removed
* fetchUserInfo replaces client.userinfo and now receives claims.sub
  so v6 can reject userinfo/id_token subject mismatches

Also:
* Cache the discovered Configuration per provider in CacheService
  (TTL 5 min) so a single login flow does not pay the HTTPS discovery
  round trip twice. Invalidation wired into saveProviderConfig,
  deleteProviderConfig, and seedOidcFromEnv via a private helper.
* Fix the testOidcDiscovery hack that passed a "discovery-probe"
  placeholder when clientId was missing; validate clientId upfront
  instead and return a clear error.
* Log fetchUserInfo failures at warn level before falling back to
  id_token claims so a subject-mismatch rejection is not silently
  hidden.

Unblocks dependabot PR #470.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-10 16:28:26 -04:00
Anso dc6764ddf5 chore(main): release 0.43.0 (#482) 2026-04-10 14:03:04 -04:00
Anso 2a2efb847e feat(release): sign and attest published docker images (#480)
Every published Sencho Docker image is now signed with Sigstore cosign
using GitHub Actions keyless OIDC, and ships with an embedded SBOM plus
SLSA provenance attestation attached as OCI referrers on the image.
Users can verify the signature and inspect the attestations themselves
before pulling an image into production.

  cosign verify saelix/sencho:<tag> \
    --certificate-identity-regexp "https://github.com/AnsoCode/Sencho/.*" \
    --certificate-oidc-issuer https://token.actions.githubusercontent.com

The release pipeline now also publishes a new moving minor tag
(saelix/sencho:X.Y, e.g. 0.42) alongside the existing latest and
immutable X.Y.Z tags, so operators who want the latest patch on a given
minor line can pin without chasing every release. Since every 0.x minor
is potentially breaking, the {{major}}-only tag is deferred until 1.0.

cosign is installed via the sigstore/cosign-installer action pinned to
a full commit SHA. The signing step batches every tag produced by
metadata-action into a single cosign invocation pinned to the built
digest, so all tags resolve to the same manifest and we save N-1
Rekor/Fulcio round trips. The job declares id-token: write so the
ambient OIDC token can be minted.

A new docs page (docs/reference/verifying-images.mdx) walks users
through installing cosign, verifying an image, and inspecting the SBOM
and provenance with docker buildx imagetools. A note calls out that
signatures start shipping with v0.43.0, so older images failing
verification is expected behavior and not tampering.
2026-04-10 13:46:27 -04:00
Anso 791d8a6306 chore(main): release 0.42.7 (#473) 2026-04-10 12:01:37 -04:00
Anso 3d69746eee fix(fleet): make local self-update flow reliable end-to-end (#472)
The "Updating Sencho..." overlay used to dismiss prematurely while the
image pull was still running, after which the local node card would get
stuck in "updating" and eventually surface a generic "Timed Out" error
while the container remained on the old version.

Three root causes are addressed:

1. The image pull was synchronous (`execFileSync`), which blocked the
   Node event loop. The overlay's health probe saw the server come back
   the moment the pull finished and reloaded the page, even though the
   container had not restarted yet. The pull is now async via
   `promisify(execFile)`, so /api/health and /api/fleet/update-status
   keep serving throughout.

2. The overlay reloaded on the first 200 from /api/health regardless of
   whether the underlying process had actually restarted. /api/health
   now exposes the gateway boot timestamp, and the overlay captures it
   pre-update and only reloads when it observes a different value. A
   wasOffline-then-online fallback handles the case where the pre-update
   fetch failed.

3. Helper container spawn errors from `docker run` were silently
   discarded, so a failed compose recreate never surfaced anywhere.
   Errors are now captured into `lastUpdateError` via the execFile
   callback and surfaced through the existing /api/fleet/update-status
   error path.

A 3-minute early-fail heuristic on the local node block surfaces a clear
failure message when the helper fails silently, instead of waiting the
full 5-minute timeout for an unknown failure.
2026-04-10 12:00:44 -04:00
Anso 8bf3a524d9 chore(main): release 0.42.6 (#469) 2026-04-10 10:05:56 -04:00
Anso c0c321227b perf: unify caching behind a single CacheService and enable HTTP compression (#468)
Replaces five ad-hoc in-process caches (project name map, templates, latest
version, fleet update status, remote node meta) with a single internal
CacheService that provides TTL, inflight-promise deduplication to protect
against thundering herd, stale-on-error fallback, and per-namespace
hit/miss/stale/size counters for observability.

Wraps the hot-path dashboard endpoints in the cache with write-path
invalidation: /api/stats (2s), /api/system/stats (3s), and
/api/stacks/statuses (3s). Keys are namespaced by nodeId so switching nodes
never serves another node's data. Every route that mutates container or
stack state calls invalidateNodeCaches(nodeId), which also drops the global
project-name-map, so user actions stay instantly reflected in the UI.

For /api/system/stats the cheap per-request network rx/tx block is kept
outside the cache so live-updating charts stay smooth while the expensive
systeminformation.currentLoad() CPU sample (~200ms) is reused across the
TTL.

Adds admin-only GET /api/system/cache-stats returning per-namespace
counters for operators who want to observe cache effectiveness.

Enables the compression middleware site-wide for JSON responses. Large
payloads like /api/templates shrink roughly 5x on the wire. SSE endpoints
are explicitly excluded via a Content-Type filter so live log tails and
metric streams are not buffered.

Bumps vitest hookTimeout to match testTimeout (15s) so parallel fork
workers do not hit the default 10s hook limit under CPU contention.

Adds 35 new tests (26 unit for CacheService, 9 integration for cached
endpoints) covering TTL expiry, inflight dedup, stale-on-error,
namespace invalidation, entry-cap safety guard, and write-path
invalidation end-to-end through Express routes.
2026-04-10 10:05:05 -04:00
Anso 0e4a8e85e2 chore(main): release 0.42.5 (#464) 2026-04-09 20:19:28 -04:00
Anso 8adcef8e47 fix(fleet): add Docker Hub fallback for version detection on private repos (#463)
* fix(fleet): add Docker Hub fallback for version detection on private repos

The GitHub Releases API returns 404 for private repos, causing the
latest version fetch to silently fail and fall back to the gateway's
own version (defeating the update detection fix from PR #454).

Now tries GitHub first, then falls back to Docker Hub tags API which
is always public. Adds console.warn logging on fetch failures per
Directive 7.

* ci: trigger CI re-run
2026-04-09 20:10:55 -04:00
Anso 746cc9eb2c chore(main): release 0.42.4 (#461) 2026-04-09 19:14:39 -04:00
Anso 8e1b9826cf fix(api): add tiered rate limiting to prevent polling lockouts (#460)
* fix(api): add tiered rate limiting to prevent polling lockouts

Replace the single global rate limiter (100 req/min/IP) with a tiered
system that separates high-frequency polling endpoints from standard
API traffic:

- Polling tier (300/min): /stats, /system/stats, /stacks/statuses,
  /metrics/historical, /health, /meta, /auth/status, /auth/sso/providers,
  /license. Exempt from the global limiter but governed by their own
  safety net to prevent resource exhaustion.
- Standard tier (200/min): All other endpoints, raised from 100.
- Webhook tier (500/min): POST /webhooks/:id/trigger, dedicated limiter
  for CI/CD platforms sharing datacenter IPs.
- Auth tier: Unchanged (5-10 attempts / 15 min).

Enterprise adaptations:
- Authenticated requests keyed by user session (JWT sub/username) instead
  of IP, preventing shared NAT/VPN environments from pooling budgets.
- Internal node-to-node traffic (node_proxy tokens) bypasses all rate
  limiters entirely.

Includes comprehensive stress tests (21 cases) validating tier
separation, node proxy bypass, and per-user keying.

* chore(deps): bump axios to 1.15.0 to fix SSRF vulnerability

Addresses GHSA-3p68-rc4w-qgx5 (NO_PROXY hostname normalization bypass).
2026-04-09 17:56:58 -04:00
Anso c812a79acc chore(main): release 0.42.3 (#458) 2026-04-09 13:15:30 -04:00
Anso 1799fca77e chore(main): release 0.42.2 (#455) 2026-04-09 12:53:09 -04:00
Anso 368bef20d3 fix(fleet): detect updates via GitHub Releases instead of gateway self-comparison (#454)
* fix(fleet): detect updates via GitHub Releases instead of gateway self-comparison

The fleet update check compared each node's version against the gateway's
own version, so the local node could never appear outdated. Now fetches
the actual latest release from GitHub Releases API with a 30-minute
in-memory cache and thundering-herd protection. The Recheck button
invalidates this cache via ?recheck=true to force a fresh lookup.

* docs(fleet): update docs to reflect GitHub Releases version detection

Replace "Gateway version" references with "Latest version" to match the
new label. Document that version comparison uses the latest GitHub release
rather than the gateway's own version, and that Recheck refreshes the
cached latest version.
2026-04-09 12:21:37 -04:00