From 923d2ee811f29115b56cffc3291e0f1b42487203 Mon Sep 17 00:00:00 2001 From: SandObserver <260779319+SandObserver@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:17:43 -0400 Subject: [PATCH] Fix Community Applications template update against a protected branch The workflow committed the release notes straight onto the default branch, which a ruleset rejects, so the v1.7.0 run failed after the release published and the template stayed on 1.6.1. Push a per-release branch and open a pull request instead, and carry the 1.7.0 notes the failed run produced. --- .github/workflows/ca-template-changes.yml | 34 ++++++- api/test/ca-template.test.js | 13 +++ api/test/workflow-hardening.test.js | 8 +- templates/stackyard.xml | 115 +++++++++++++++++----- 4 files changed, 138 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ca-template-changes.yml b/.github/workflows/ca-template-changes.yml index fbf60240..bf3bd0c2 100644 --- a/.github/workflows/ca-template-changes.yml +++ b/.github/workflows/ca-template-changes.yml @@ -4,16 +4,17 @@ on: release: types: [published] -# Commits the updated template back to the default branch. The repository -# default is read, so the write is granted here and nowhere else. +# Opens a pull request against the default branch. The repository default is +# read, so the writes are granted here and nowhere else. permissions: contents: write + pull-requests: write jobs: update: runs-on: ubuntu-latest steps: - # Commit onto the default branch, not the tag the release points at: a + # Branch from the default branch, not the tag the release points at: a # tag checkout is detached and the push would go nowhere. - name: Checkout default branch uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 @@ -38,17 +39,40 @@ jobs: # The checkout keeps no credentials, so the token authenticates this one # push and is never left in the runner's git config. - - name: Commit + # + # A pull request, never a direct push: the default branch requires one. + # Checks do not start on a pull request opened with GITHUB_TOKEN. Merging + # this one needs the ruleset bypass, or a re-run of the checks. + - name: Open a pull request if: steps.changes.outputs.changed == 'true' env: VERSION: ${{ github.event.release.tag_name }} - BRANCH: ${{ github.event.repository.default_branch }} + BASE: ${{ github.event.repository.default_branch }} REPO: ${{ github.repository }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -euo pipefail + BRANCH="docs/ca-template-${VERSION}" git config user.name 'github-actions[bot]' git config user.email '41898282+github-actions[bot]@users.noreply.github.com' + git checkout -b "${BRANCH}" git add templates/stackyard.xml git commit -m "Docs: describe ${VERSION} in the Community Applications template" git push "https://x-access-token:${GH_TOKEN}@github.com/${REPO}.git" "HEAD:${BRANCH}" + gh pr create \ + --base "${BASE}" \ + --head "${BRANCH}" \ + --title "Docs: describe ${VERSION} in the Community Applications template" \ + --label documentation \ + --body "$(printf '%s\n' \ + '**Summary**' \ + "- Copy the ${VERSION} changelog section into the Community Applications template." \ + '' \ + '**Testing**' \ + 'The template was validated as well-formed before this branch was pushed.' \ + '' \ + '**Checklist**' \ + '- [x] Stays within the project constraints: one container, no runtime dependencies, no build step (see CONTRIBUTING.md).' \ + '- [ ] Tests added or updated for new logic, and the full suite, lint, and typechecks pass.' \ + '- [x] Docs updated if behavior or configuration changed.' \ + '- [ ] CHANGELOG.md updated under Unreleased if the change is user-visible.')" diff --git a/api/test/ca-template.test.js b/api/test/ca-template.test.js index ecdae30d..1ffe9734 100644 --- a/api/test/ca-template.test.js +++ b/api/test/ca-template.test.js @@ -82,6 +82,19 @@ test('both documents use the repository path with its real capitalisation', () = } }); +/* The default branch requires a pull request. A workflow that pushes the + template straight at it is rejected by the ruleset and the release notes + never reach the listing. */ +test('the template update opens a pull request instead of pushing to the default branch', () => { + const src = fs.readFileSync(path.join(ROOT, '.github', 'workflows', 'ca-template-changes.yml'), 'utf8'); + const commands = src + .split('\n') + .filter(line => !/^\s*#/.test(line)) + .join('\n'); + assert.match(commands, /gh pr create/, 'the update no longer opens a pull request'); + assert.doesNotMatch(commands, /git push[^\n]*HEAD:\$\{BASE\}/, 'a direct push to the default branch is rejected'); +}); + /* The runner image has no xmllint, so a workflow that reaches for it fails at step one. Both validate through the committed script instead. */ test('the workflows validate with the committed script, not xmllint', () => { diff --git a/api/test/workflow-hardening.test.js b/api/test/workflow-hardening.test.js index bf9068d2..ae29238b 100644 --- a/api/test/workflow-hardening.test.js +++ b/api/test/workflow-hardening.test.js @@ -52,13 +52,13 @@ test('no workflow grants a write scope it does not need', () => { lets the job mint a short-lived OIDC token, which is what cosign exchanges for a Sigstore certificate when it signs the released image. Keyless signing needs it, and it is the reason there is no private key to hold. */ - /* The CA template's release notes are committed back to the default branch, - which is the only thing that write scope covers. The checkout still keeps - no credentials: the push authenticates on its own. */ + /* The CA template's release notes go to a branch and a pull request, which is + all those two scopes cover. The checkout still keeps no credentials: the + push authenticates on its own. */ const allowed = { 'workflows/release.yml': ['packages: write', 'id-token: write'], 'workflows/codeql.yml': ['security-events: write'], - 'workflows/ca-template-changes.yml': ['contents: write'], + 'workflows/ca-template-changes.yml': ['contents: write', 'pull-requests: write'], }; const bad = []; for (const [f, src] of workflows) { diff --git a/templates/stackyard.xml b/templates/stackyard.xml index aabff05a..bd93bc96 100644 --- a/templates/stackyard.xml +++ b/templates/stackyard.xml @@ -19,42 +19,111 @@ If Stackyard is useful to you, you can buy me a coffee. https://buymeacoffee.com/sandobserver -### 1.6.1 - 2026-08-14 +### 1.7.0 - 2026-08-16 + +### Added + +- Light theme for the Settings pages, with Settings Display Mode in Settings > + Appearance: System Default, Light or Dark. Stored per device. + +- Keep Screen Awake in Settings > Appearance, off by default. Needs HTTPS. + +- Show From on a live activity badge, to badge only counts at or above a number. + +- Install from Unraid Community Applications, with a template in `templates/`. + +### Changed + +- Text on both pages now follows one type scale, so some sizes and line spacing + shift slightly. + +- Widget colours now match the rest of the app. Reds, blues, greens and greys + that had been left on older values are corrected. + +- Settings controls are redrawn: switches are wider with a capsule knob, slider + tracks are thicker, and groups are more rounded. + +- The wallpaper brightness slider now has the same handle as the colour sliders. + +- Each colour slider handle shows the value it is set to. + +- Group headings and their help text now line up with the settings above and + below them. + +- The settings sidebar is wider, with taller items and a rounded selection. + +- The selected tab on a phone is marked with a pill instead of a coloured + label. + +- Widget tiles and dock icons are rounded correctly, and stay so at every icon + and dashboard size. + +- Either-or settings are now a segmented control instead of radio dots. + +- Buttons in a dialog are taller and rounded. + +- A long settings label now keeps its line and the value beside it shortens, + instead of the label breaking in two. + +- Unsplash API Key is now just API Key, under a Source row that already names + Unsplash. + +- Row separators now start level with the row's label instead of spanning the + full width. + +- Settings on a phone use the larger phone text size. On a desktop the panel + keeps its denser size. + +- Widgets on a page you are not looking at now poll four times less often, and + refresh when you swipe back to them. + +- Badge and health targets that keep failing are contacted less often, so an + offline service no longer slows every other tile on every refresh. + +- Scripts and stylesheets are now cached for a year instead of revalidated on + every load. Their URLs change whenever the file does. + +- The logo is redrawn, and its arc now follows the accent colour. ### Fixed -- Phone home screen no longer starts under the status bar in a home-screen - install. The first row clears the clock and the island. +- Home screen no longer leaves a dead strip below the dock in a home-screen + install on iOS. + +- App icons now use the current logo, and the browser tab icon follows the + light or dark theme. + +- Colour and brightness slider tracks draw round ends on a touch device instead + of tapering to a point. -- Settings reserves the status bar area on a phone. +- Hue, saturation and brightness sliders no longer stretch across the row on a + phone. -- Notification badges inside a folder no longer get trimmed at the page edge or - bleed into the next page. +- Slider fills and colour ramps now run the same way as the handle in + right-to-left languages. -- Opening a folder no longer puts a focus ring on the first app, on a phone or - on the desktop. +- Saturation, brightness and wallpaper brightness sliders now draw a thin track + on a phone, matching hue. -- A long error in Admin now stays on screen long enough to read, up to fifteen - seconds. +- Settings no longer flashes the desktop sidebar before the phone layout + appears. -- Backup placeholder no longer moves or reshuffles when a card is hovered or - tapped. +- Dock and the Settings tab bar now sit as close to the bottom of the screen as + to the sides. -- The App, Widget and Folder tiles under Add New show their names instead of - their internal keys. +- Remove the stray Support link from Settings > General. -- The Backup widget shows the job picker for the provider you picked. Kopia - showed the Duplicati picker as well, and Duplicati showed no picker at all. +- App title toggles in Settings > Appearance now persist across a reload. -- A badge or widget field blocked for pointing at a private address now names - `ALLOW_PRIVATE_IPS=true` as the setting that allows it. The advice was added - in 1.6.0 but never appeared. +- Connections map tooltips now use the system font on Android, Windows and + Linux instead of falling back to a serif. -- A widget settings Fetch marks a blocked private address as a warning, the - same as a badge test, instead of a hard error. +- Saving on Settings > Appearance no longer reports "Wallpaper saved" when + something else on the page was saved. -- A badge extract path ending in `count` now reads a JSON field of that - name. It only counts an array when the value is an array. +- The login and set-password screens, the phone tab bar, the logging level and + wallpaper source menus, the version line and the app, widget and widget + configuration forms are now translated instead of always showing English. 8700 /mnt/user/appdata/stackyard/data