diff --git a/.github/workflows/branch-protection.yml b/.github/workflows/branch-protection.yml index 666fc767..d3e40cad 100644 --- a/.github/workflows/branch-protection.yml +++ b/.github/workflows/branch-protection.yml @@ -8,4 +8,10 @@ on: jobs: protect: + # The callee's `check-branch` job is a single bash comparison of + # `github.base_ref` against `github.head_ref` — no checkout, no network, no + # API call. It needs nothing, so it gets nothing. `{}` is an explicit empty + # grant, which is what satisfies actions/missing-workflow-permissions; an + # ABSENT block means "whatever the repo default is", which is the finding. + permissions: {} uses: ConductionNL/.github/.github/workflows/branch-protection.yml@main diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 878d0952..20937988 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -83,6 +83,36 @@ on: # be redder than a PR — that is the honest answer, not a regression. workflow_dispatch: +# Permission CEILING for the called quality pipeline, NOT a grant. Copied +# verbatim from openconnector, where this exact block is live on `development` +# with all ~30 quality jobs green — so it is a measured ceiling, not a guess. +# +# ⚠️ Most jobs in the callee declare NO permissions of their own (only +# journeydoc-capture and features-extract do), which means they inherit THIS +# ceiling exactly. Every entry below is load-bearing: +# +# contents: write journeydoc-capture and update-baseline `git push` +# the regenerated screenshots / coverage baseline +# actions: write journeydoc-capture re-dispatches downstream work +# (a GITHUB_TOKEN push does not fire workflow_run) +# issues / pull-requests: write +# the Quality Report comment — `github.rest.issues +# .createComment`, which 403s under contents+packages +# read alone (quality.yml notes this at its own step) +# packages: read pulling org images for the Nextcloud test matrix +# +# ⚠️ Do NOT "tighten" any of these to `read`. GitHub statically validates the +# called workflow's DECLARED job permissions against this grant — including for +# jobs an `if:` will skip — so capping one makes the whole call fail to START: +# zero jobs, no annotations, and a Code Quality run that is absent rather than +# red. That is quieter than the outage it would cause. +permissions: + contents: write + actions: write + issues: write + pull-requests: write + packages: read + jobs: quality: uses: ConductionNL/.github/.github/workflows/quality.yml@main diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 5b3aa456..1de66271 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -8,6 +8,25 @@ on: jobs: deploy: + # Permission CEILING for the called documentation workflow, not a grant. + # The callee has three jobs and this block is their UNION, which is what the + # token already resolves to today: + # build contents: read + # deploy contents: write (peaceiris/actions-gh-pages pushes to gh-pages) + # image contents: read, packages: write (buildx push to GHCR) + # + # ⚠️ `packages: write` is load-bearing at RUNTIME, not merely statically: + # the callee's `build-image` input DEFAULTS TO TRUE, so the `image` job + # really does run on a push to `documentation` and really does push to + # GHCR. Dropping it 403s that push. + # + # It would be required even if that job were disabled, because GitHub + # validates the callee's DECLARED job permissions against this ceiling + # before dispatch — including for jobs an `if:` will skip — so a too-low + # ceiling makes the whole call fail to start rather than run with less. + permissions: + contents: write + packages: write uses: ConductionNL/.github/.github/workflows/documentation.yml@main with: cname: softwarecatalog.conduction.nl diff --git a/.github/workflows/issue-triage.yml b/.github/workflows/issue-triage.yml index e2603654..ac9a743c 100644 --- a/.github/workflows/issue-triage.yml +++ b/.github/workflows/issue-triage.yml @@ -12,6 +12,15 @@ on: jobs: triage: + # Permission CEILING for the called workflow, not a grant. All three jobs in + # the callee (triage-single, triage-decision, backlog-triage) already declare + # exactly `issues: write` + `contents: read` for themselves, so this restates + # the grant the token has today and changes nothing that runs. `issues: write` + # is the label-and-assign step; the ProjectsV2 board step is disabled because + # GITHUB_TOKEN cannot reach it at any permission level (ConductionNL/.github#432). + permissions: + issues: write + contents: read uses: ConductionNL/.github/.github/workflows/issue-triage.yml@main with: app-name: softwarecatalog diff --git a/.github/workflows/openspec-sync.yml b/.github/workflows/openspec-sync.yml index bf06b8e8..541e3221 100644 --- a/.github/workflows/openspec-sync.yml +++ b/.github/workflows/openspec-sync.yml @@ -8,6 +8,14 @@ on: jobs: sync: + # Permission CEILING for the called workflow, not a grant. The callee's + # `sync` job already declares exactly `issues: write` + `contents: read`, so + # this restates today's effective token. It creates/updates the OpenSpec + # tracking issues; the board placement is disabled (GITHUB_TOKEN cannot do + # ProjectsV2 — ConductionNL/.github#432). + permissions: + issues: write + contents: read uses: ConductionNL/.github/.github/workflows/openspec-sync.yml@main with: app-name: softwarecatalog diff --git a/.github/workflows/release-beta.yml b/.github/workflows/release-beta.yml index 23a2ab0c..711c3124 100644 --- a/.github/workflows/release-beta.yml +++ b/.github/workflows/release-beta.yml @@ -7,6 +7,19 @@ on: jobs: release: + # Permission CEILING for the called release workflow, not a grant. The + # callee's `release` job already declares `contents: write` for itself, so + # this restates today's effective token and changes nothing that runs. + # `contents: write` cuts the tag and uploads the release asset + # (ncipollo/release-action, svenstaro/upload-release-action); the App Store + # publish authenticates with NEXTCLOUD_APPSTORE_TOKEN, not GITHUB_TOKEN, so + # it needs nothing here. + # + # ⚠️ Not `contents: read`. A caller block CAPS the callee — GitHub validates + # the callee's declared job permissions against it — so a lower ceiling makes + # the call fail to START (zero jobs) rather than run with less. + permissions: + contents: write uses: ConductionNL/.github/.github/workflows/release-beta.yml@main with: app-name: softwarecatalog diff --git a/.github/workflows/release-development.yml b/.github/workflows/release-development.yml index 9bcf84b1..0f295026 100644 --- a/.github/workflows/release-development.yml +++ b/.github/workflows/release-development.yml @@ -29,6 +29,17 @@ concurrency: jobs: release: + # Permission CEILING for the called release workflow, not a grant. The + # callee's `release` job already declares `contents: write` for itself, so + # this restates today's effective token and changes nothing that runs. + # `contents: write` cuts the tag and publishes the prerelease + .tar.gz that + # the App Versions app installs from. This channel never touches the App + # Store, so nothing else is needed. + # + # ⚠️ Not `contents: read`. A caller block CAPS the callee, so a lower ceiling + # makes the call fail to START rather than run with less. + permissions: + contents: write uses: ConductionNL/.github/.github/workflows/release-beta.yml@main with: app-name: softwarecatalog diff --git a/.github/workflows/release-stable.yml b/.github/workflows/release-stable.yml index 34a2b6b6..4cdbad92 100644 --- a/.github/workflows/release-stable.yml +++ b/.github/workflows/release-stable.yml @@ -7,6 +7,16 @@ on: jobs: release: + # Permission CEILING for the called release workflow, not a grant. The + # callee's `release` job already declares `contents: write` for itself, so + # this restates today's effective token and changes nothing that runs. + # `contents: write` cuts the tag and uploads the release asset; the App Store + # publish authenticates with NEXTCLOUD_APPSTORE_TOKEN, not GITHUB_TOKEN. + # + # ⚠️ Not `contents: read`. A caller block CAPS the callee, so a lower ceiling + # makes the call fail to START rather than run with less. + permissions: + contents: write uses: ConductionNL/.github/.github/workflows/release-stable.yml@main with: app-name: softwarecatalog diff --git a/.github/workflows/sync-to-beta.yml b/.github/workflows/sync-to-beta.yml index 7d2dacae..c21f6f0d 100644 --- a/.github/workflows/sync-to-beta.yml +++ b/.github/workflows/sync-to-beta.yml @@ -7,4 +7,15 @@ on: jobs: sync: + # Permission CEILING for the called workflow, not a grant. The callee's + # `create-pr` job already declares exactly these two, so this restates + # today's effective token. It runs `gh pr list` / `gh pr create` to keep the + # standing development -> beta release PR open, which needs + # `pull-requests: write`; `contents: write` is the checkout it pushes from. + # + # ⚠️ `contents: read` alone would leave the PR step 403-ing at runtime — a + # red release-sync that looks like a merge conflict. + permissions: + contents: write + pull-requests: write uses: ConductionNL/.github/.github/workflows/sync-to-beta.yml@main diff --git a/src/views/Dashboard.vue b/src/views/Dashboard.vue index 8eda9c5a..e43c0ad8 100644 --- a/src/views/Dashboard.vue +++ b/src/views/Dashboard.vue @@ -480,20 +480,32 @@ export default { /** * Format date for display * + * Renders as `17/08/2026, 08:33`. `toLocaleDateString` is correct here + * even though the result carries a time: explicit `hour`/`minute` + * options are honoured (ECMA-402 ToDateTimeOptions only supplies + * date-part DEFAULTS when none are given), so this is not the + * "toLocaleDateString silently drops the time" trap it resembles. + * + * A trailing `.replace(',', ',')` was removed here. It replaced the + * comma with itself — a no-op, flagged as js/identity-replacement. + * It was born in that identical form (5c33f0b, "Working on the detail + * pages"), so no working behaviour was ever lost and no intent is + * recorded anywhere to recover. Deleting it is byte-for-byte + * output-preserving, verified against the string above; guessing at + * `.replace(',', '')` would have invented a UI change nothing asked for. + * * @param {Date} date - Date to format * @return {string} Formatted date string * @spec openspec/specs/fe-shell-navigation/spec.md */ formatDate(date) { - return date - .toLocaleDateString('en-GB', { - day: '2-digit', - month: '2-digit', - year: 'numeric', - hour: '2-digit', - minute: '2-digit', - }) - .replace(',', ',') + return date.toLocaleDateString('en-GB', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + }) }, /**