Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
140 commits
Select commit Hold shift + click to select a range
44ea073
security fixes
ebremer Jul 16, 2026
e604104
code cleanup
ebremer Jul 17, 2026
975832e
jena-permissions fixes
ebremer Jul 17, 2026
416a06b
bump vandegraph to 0.2.0-SNAPSHOT
ebremer Jul 17, 2026
f5352f6
rewrite Stacks on vandegraph row filtering and node-keyed selection
ebremer Jul 17, 2026
dfb4f57
add LWSContainers: LWS tree browser with access properties and preview
ebremer Jul 17, 2026
308bc1a
resolve LWSContainers previews through vandegraph media bindings
ebremer Jul 17, 2026
1800e61
wrap Zephyr as hal:ZephyrViewer/Editor selected by media-binding shapes
ebremer Jul 17, 2026
b95c744
document the storage UIs (docs/lws/ui.md)
ebremer Jul 17, 2026
dd2639e
expose an ACP-authorized IIIF Image service endpoint on each LWS storage
ebremer Jul 18, 2026
7bbbfcd
wire Halcyon's IIIF engine into the LWS storages' image service
ebremer Jul 18, 2026
3778323
document the /.iiif endpoint; ignore HalcyonLWS test TDB2 dir
ebremer Jul 18, 2026
d7f615f
record whole-slide media types on mirror adoption (.svs/.ndpi -> imag…
ebremer Jul 18, 2026
255511f
let the signed-in session pay for LWS IIIF tiles
ebremer Jul 18, 2026
d372bc8
forward LWS image identifiers from the global /iiif to the owning sto…
ebremer Jul 18, 2026
e04ab00
record real media types for opaque uploads (browser .svs -> image/tiff)
ebremer Jul 18, 2026
7206f66
self-heal opaque mirror media types on reconcile
ebremer Jul 18, 2026
5b77dbe
LWS-native Zephyr stacks: born, saved, listed and reopened in the sto…
ebremer Jul 18, 2026
d5e12e2
always revalidate /zephyr/** modules, not only in dev mode
ebremer Jul 18, 2026
ccc57b4
LWS Containers: add Delete to the right-click context menu
ebremer Jul 18, 2026
6a1984e
store LWS stacks as relative Turtle: the file names itself <>
ebremer Jul 18, 2026
d6b19e9
birth annotation JSONs beside the stack file, and replace them condit…
ebremer Jul 18, 2026
c654f5e
document the relative stack file contract in the LWS UI notes
ebremer Jul 18, 2026
bafe9c8
scan RDF documents with the RDF document reader, and re-scan the stor…
ebremer Jul 18, 2026
65dc88a
open typed stack Turtle in Zephyr: bind text/turtle AND zeph:Stack co…
ebremer Jul 18, 2026
904012c
bind BeakGraph HDF5 to the Zephyr viewer
ebremer Jul 18, 2026
bfb2d4d
close the SPARQL bypass in the ACP-secured dataset view
ebremer Jul 18, 2026
5495342
/rdf2: read-only SPARQL over the LWS module's own TDB2
ebremer Jul 18, 2026
8b65eeb
parameterize the SPARQL page over both endpoints (/rdf and /rdf2)
ebremer Jul 18, 2026
847be47
mirror-storage mounts: other physical disks behind sub-containers
ebremer Jul 18, 2026
4f0e8b0
/rdf2?iri=: a SPARQL endpoint for every BeakGraph file in a storage
ebremer Jul 18, 2026
8cbf5cc
point Graph3D at either triple store
ebremer Jul 18, 2026
ae84be1
remove the legacy Images-screen cluster
ebremer Jul 18, 2026
d1af640
remove the remaining legacy catalog pages
ebremer Jul 18, 2026
4ebd23e
move user color classes to the LWS storage
ebremer Jul 18, 2026
755ad37
drop the color-classes legacy migration - there was nothing to migrate
ebremer Jul 18, 2026
c4139f4
remove the legacy LDP servlet and the /upload page
ebremer Jul 18, 2026
aaa59be
sweep the orphaned legacy data out of the classic store at startup
ebremer Jul 18, 2026
0c3b2d0
replace /admin with the instance-configuration page
ebremer Jul 18, 2026
2047643
make /stacks LWS-native; retire the triple-store stack paths
ebremer Jul 18, 2026
fee5d97
delete the effectively-dead legacy tail
ebremer Jul 18, 2026
f0ee52e
remove Zephyr2; rename Zephyr3 to Zephyr
ebremer Jul 18, 2026
82c3c80
Images: an LWS-native list built on the vandegraph table stack
ebremer Jul 18, 2026
bfefc3b
rework /user/account: the caller's own data, vandegraph-tabled
ebremer Jul 18, 2026
156660a
serve scriptable LWS content sandboxed (nosniff + CSP sandbox)
ebremer Jul 18, 2026
266db46
render stored HTML in the LWS preview - sandboxed, as the default viewer
ebremer Jul 18, 2026
b47a4be
TipTap editing for stored HTML - the bound editor behind a pane Edit …
ebremer Jul 18, 2026
461a905
full-screen toggle for the LWS preview pane
ebremer Jul 19, 2026
df10b52
Monaco code viewing/editing in the LWS preview pane
ebremer Jul 19, 2026
f415e70
adopt vandegraph's text/plain-in-Monaco default in the LWS preview
ebremer Jul 19, 2026
d6ac5e6
Turtle opens in Monaco via vandegraph's turtle language; stacks keep …
ebremer Jul 19, 2026
ae9835f
version 0.9.0 (last tag 0.8.0); use beakgraph 0.18.0
ebremer Jul 19, 2026
0c282c2
HalcyonMCP module: Spring AI 2.0 MCP server at /mcp (skeleton + plan)
ebremer Jul 19, 2026
0e493c0
MCP-1: bearer auth on /mcp via the shared LWS token verifier
ebremer Jul 19, 2026
46ab800
MCP-2: per-call principal — transport context carries the verified ca…
ebremer Jul 19, 2026
3bdcfa2
MCP-3: LwsClient moves to HalcyonLWS (com.ebremer.lws.client) as the …
ebremer Jul 19, 2026
19e076e
MCP-5: Guardrails - byte/row/time caps and the read-only, SERVICE-fre…
ebremer Jul 19, 2026
c630250
MCP-4: runtime-verified /mcp end to end; README records the auth desi…
ebremer Jul 19, 2026
a525077
MCP-6: lws_storages tool; McpCaller carries the caller's token to LWS…
ebremer Jul 19, 2026
5297213
MCP-7: lws_list - protocol-cursor container listing as the caller
ebremer Jul 19, 2026
a3fd1eb
MCP-8: lws_read - bounded, text-gated resource read as the caller
ebremer Jul 19, 2026
be92d60
MCP-9: sparql_query - read-only, bounded SPARQL run as the caller's W…
ebremer Jul 19, 2026
a1f5276
MCP-10: find_slides / list_stacks - ACP-filtered type-search discovery
ebremer Jul 19, 2026
72c2bd4
MCP-11: iiif_info / iiif_thumbnail via the storage IIIF endpoint; P1 …
ebremer Jul 19, 2026
1d485e7
MCP-12: lws_put - conditional replace / create-in-parent as the caller
ebremer Jul 19, 2026
2e82ad8
MCP-13: lws_request_access - file an LWS access request as the caller…
ebremer Jul 19, 2026
2fb84d1
MCP-15: MCP resources (agent guide) + canonical-workflow prompts
ebremer Jul 19, 2026
340bfa6
MCP-16: prompt-argument completion; documented output/pagination conv…
ebremer Jul 19, 2026
1decf0e
MCP-17: per-tool audit + optional metrics, per-principal rate limitin…
ebremer Jul 19, 2026
090a09a
MCP-18: ops posture - STREAMABLE-only caller plumbing, version pin, n…
ebremer Jul 19, 2026
7feabbc
MCP-F1: end-to-end MCP client integration test; fix arg-name (-parame…
ebremer Jul 19, 2026
6e7bb13
MCP-F3: pin slf4j.provider to Logback at launch (deterministic vs Bea…
ebremer Jul 19, 2026
c8e14f1
LWS-S3-1: PathKeyedStore contract axis; servlet stops naming MirrorCo…
ebremer Jul 20, 2026
e19531c
LWS-S3-2: MaterializedContentStore - local cache face for remote key-…
ebremer Jul 20, 2026
686c28e
LWS-S3-3: ContentStoreProvider SPI + registry; :hasBackend rides the …
ebremer Jul 20, 2026
6b90e95
LWS-S3-4: HalcyonLWS-S3 module - S3-backed ContentStore via the provi…
ebremer Jul 20, 2026
3769438
LWS-S3-5: app wiring - runtime dep, per-storage boot validation, oper…
ebremer Jul 20, 2026
ddc720c
LWS-OIDC: design plan for LWS-OIDC credential support alongside gener…
ebremer Jul 21, 2026
f75ca99
LWS-OIDC-1: route bearer auth through a CredentialVerifier chain (no …
ebremer Jul 21, 2026
0c44afe
LWS-OIDC-2a: SsrfGuard for the LWS-OIDC verifier's outbound fetches
ebremer Jul 21, 2026
eb74cbc
LWS-OIDC-2b: CidResolver — dereference the WebID and check the OpenId…
ebremer Jul 21, 2026
ae7ebe5
LWS-OIDC-2c: OidcKeys — per-issuer discovery + JWKS with normal TLS a…
ebremer Jul 21, 2026
99eb3dc
LWS-OIDC-2d: LwsOidcVerifier — verify LWS-OIDC credentials, wired in …
ebremer Jul 21, 2026
adc6869
LWS-OIDC-3: enable-flag config example + security docs for the LWS-OI…
ebremer Jul 21, 2026
f8c4c6a
LWS-OIDC-3b: prove an LWS identity drives storage access via an acp:i…
ebremer Jul 21, 2026
649ab8c
WEBID-LOGIN-B1: WebID interactive-login backend (discovery + PKCE + I…
ebremer Jul 21, 2026
a9db01d
WEBID-LOGIN-B2: /webid-login + /webid-callback servlets + routing (of…
ebremer Jul 21, 2026
c15d78a
WEBID-LOGIN-B3: seat the WebID identity in the session + a WebID-logi…
ebremer Jul 22, 2026
f9b6c8e
WEBID-LOGIN-B5: RFC 7591 dynamic client registration for WebID login
ebremer Jul 22, 2026
54af65d
WEBID-LOGIN: seat the identity by rebuilding the session on callback
ebremer Jul 22, 2026
e0d06a4
WEBID-LOGIN: let a WebID-authenticated request past the pac4j filter
ebremer Jul 22, 2026
e69b738
Fix access-request panel: add the webid label to the form, not the panel
ebremer Jul 22, 2026
6575b3b
WEBID-LOGIN: local WebID->role mapping (lws-oidc.json webIdGroups)
ebremer Jul 22, 2026
c6c10aa
WEBID-LOGIN: seat roles + username, present the token to LWS storage …
ebremer Jul 22, 2026
824eaca
WEBID-LOGIN: recognise the WebID session in RequestPrincipal (fix ser…
ebremer Jul 22, 2026
5f2b928
WEBID-LOGIN: accept WebID (LWS-OIDC) credentials at the Fuseki /rdf s…
ebremer Jul 22, 2026
38e9225
LWS-SPARQL: each BeakGraph resource is a SPARQL endpoint at its own URL
ebremer Jul 22, 2026
f4550da
LWS-SPARQL: let SERVICE federate to this server's own (self-signed) H…
ebremer Jul 22, 2026
2548f5a
LWS: advertise the core /rdf2 SPARQL endpoint in the storage description
ebremer Jul 22, 2026
d53a3d1
LWS: capability SPI — per-resource SPARQL as a ResourceCapability (St…
ebremer Jul 22, 2026
00e584e
LWS: migrate IIIF onto the capability SPI (EndpointCapability, Stage 2)
ebremer Jul 22, 2026
0dcdea7
LWS: store-wide SPARQL as an advertisement-only capability (Stage 3)
ebremer Jul 22, 2026
53b83af
Ignore PLAN-CAPABILITY.md (local planning doc)
ebremer Jul 22, 2026
1e1956d
Remove the Stacks feature (page, /savestack, StackStore)
ebremer Jul 22, 2026
389055f
Remove the CollectionsAndResources catalog graph plumbing
ebremer Jul 22, 2026
7998c1b
Remove the /rdf SPARQL endpoint (loopback Fuseki + Shiro stack)
ebremer Jul 22, 2026
03a9a56
Remove LegacyDataCleanup (its one-time migration purge is done)
ebremer Jul 22, 2026
4ae8cda
Restore a read-only Stacks list + stack saving (LWS-native)
ebremer Jul 22, 2026
bc7e02e
remove ebremer.com reference
ebremer Jul 22, 2026
12ecf34
remove unused import
ebremer Jul 22, 2026
d817747
LWS: move the store-wide SPARQL engine into the module (LwsSparql)
ebremer Jul 22, 2026
b716f08
Show the Color Classes menu item to every signed-in user
ebremer Jul 22, 2026
863c9c2
Fix Color Classes 400 for WebID logins: getUser() must be the short name
ebremer Jul 22, 2026
4b27d7b
Zephyr: stop edge tiles smearing their last texel past the image edge
ebremer Jul 23, 2026
b9f3650
HalcyonLWS: implement RFC 9530 Digest Fields
ebremer Jul 23, 2026
2c82392
Add IMPLEMENTED-SPECS.md: catalog of implemented RFCs and specifications
ebremer Jul 23, 2026
b267ea1
HalcyonLWS: implement JSON Patch (RFC 6902) on JSON data resources
ebremer Jul 23, 2026
134bc46
IMPLEMENTED-SPECS: move RFC 6902 JSON Patch to implemented
ebremer Jul 23, 2026
da10ee5
defaultapplication.yml: fix fresh-install crash (SSL bundle 'server' …
ebremer Aug 12, 2026
ad4c274
Error pages: render real status and message instead of masking as 404
ebremer Aug 12, 2026
a93d65d
defaultapplication.yml: sensible production logging defaults
ebremer Aug 13, 2026
a29515d
LWS: every 405 carries Allow (RFC 9110 MUST)
ebremer Aug 19, 2026
b15d52d
LWS: a refused write no longer destroys the mirror resource it was re…
ebremer Aug 19, 2026
e601923
LWS: a conflicting DELETE says 409 before it says 428
ebremer Aug 19, 2026
b0d806f
LWS: a public storage says 404 for what is not there, not 401
ebremer Aug 20, 2026
eb95fb0
Keycloak becomes optional: comment out :AuthServer and LWS auth carri…
ebremer Aug 20, 2026
772eba4
LWS: DELETE honours If-Match, it no longer demands one
ebremer Aug 21, 2026
6f5989c
Declare the repository's line-ending policy in .gitattributes
ebremer Sep 1, 2026
03263f6
Fix the build: BeakGraphQueryCapabilityTest misses LwsResource.sha256
ebremer Sep 1, 2026
e0d099c
Ignore .claude/settings.local.json
ebremer Sep 1, 2026
36e0fc2
ci: build and test next, the branch development actually lands on
ebremer Sep 1, 2026
98cc87a
Close the XXE in XMP parsing: uploaded images could read server files
ebremer Sep 1, 2026
22ef42a
Test AcpEngine, the LWS authorization decision engine (F096)
ebremer Sep 1, 2026
24e539f
One egress policy for caller-supplied SPARQL and webhook inboxes
ebremer Sep 1, 2026
6b8d400
Scope what a client may write into, and delete from, the ACP graph
ebremer Sep 1, 2026
aea06e7
Make the security URL patterns honest, and stop /iiif trusting them
ebremer Sep 2, 2026
0f9386f
Fix the URL mapping audit, which stopped the server from starting
ebremer Sep 2, 2026
74fd5d2
Jena 6.2.0, Spring AI 2.0.1, and the test migration 6.2.0 forces
ebremer Sep 2, 2026
9e72476
Check a variable SERVICE endpoint when it resolves, instead of refusi…
ebremer Sep 2, 2026
0213da6
SPARQL editor: offer the ActivityStreams prefix
ebremer Sep 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
65 changes: 65 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Line-ending policy for the Halcyon repository.
#
# The repository's canonical form is LF: every blob already committed uses LF.
# Without this file, git had no line-ending policy at all (no .gitattributes,
# core.autocrlf unset), so a working tree checked out or edited by a Windows
# tool acquired CRLF and every one of the ~5,300 tracked files reported as
# modified. That made `git diff`, `git blame` and code review unusable.
#
# `text=auto eol=lf` normalizes to LF on commit and checks out LF on every
# platform, so the working tree cannot drift back regardless of which git
# binary (WSL or Windows) last touched it.

* text=auto eol=lf

# --- Explicit text types -----------------------------------------------------
# Declared rather than left to git's heuristic, so a file that happens to
# contain a NUL byte early on is still treated as source.
*.java text eol=lf
*.js text eol=lf
*.mjs text eol=lf
*.ts text eol=lf
*.map text eol=lf
*.css text eol=lf
*.scss text eol=lf
*.less text eol=lf
*.html text eol=lf
*.ftl text eol=lf
*.xml text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.json text eol=lf
*.jsonld text eol=lf
*.ttl text eol=lf
*.md text eol=lf
*.txt text eol=lf
*.ini text eol=lf
*.properties text eol=lf
*.svg text eol=lf

# Executable scripts must be LF or the shebang breaks.
*.sh text eol=lf
*.py text eol=lf

# --- Binary: never normalize, never diff as text -----------------------------
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.icns binary
*.webp binary
*.woff binary
*.woff2 binary
*.ttf binary
*.eot binary
*.otf binary
*.wasm binary
*.jar binary
*.war binary
*.zip binary
*.gz binary
*.pdf binary
*.h5 binary
*.svs binary
*.dcm binary
32 changes: 27 additions & 5 deletions .github/workflows/changelog-and-contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,25 @@ on:
# branches:
# - master

# L16: this job commits and pushes, so it needs contents: write — but it should get
# exactly that and nothing else, rather than inheriting the repository default.
permissions:
contents: write

jobs:
generate_changelog:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

# L16: pinned by SHA — a mutable tag lets the action's owner run new code with
# this job's push-capable token. (Was @v3; the SHA below is that same v3 line.)
- uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
with:
# The changelog is built from `git log` and `git describe --tags`, both of
# which see nothing useful in the default depth-1 checkout: no history and
# no tags, so "last_tag" was always empty and the "since last tag" branch
# below could never be taken.
fetch-depth: 0

- name: Generate Changelog and Contributors
run: |
# Install necessary tools
Expand All @@ -32,13 +45,22 @@ jobs:
# Generate a list of contributors
output=$(git log --format='%aN' | sort -u)
echo "$output" > contributors.txt

- name: Commit and Push Changes
# L16: github.ref goes through env rather than being interpolated into the
# script, same reasoning as the release-tag uploads in main.yml. Also: commit
# only when something actually changed — an unconditional `git commit` fails
# the job on a no-op run, which is why this workflow is dispatch-only.
run: |
git config --local user.name "github-actions[bot]"
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git add changelog.md contributors.txt
git commit -m "chore: update changelog and contributors"
git push origin HEAD:${{ github.ref }}
if git diff --staged --quiet; then
echo "No changelog or contributor changes to commit."
else
git commit -m "chore: update changelog and contributors"
git push origin "HEAD:$TARGET_REF"
fi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TARGET_REF: ${{ github.ref }}
72 changes: 72 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: ci

# F2: the whole point of this file. Before it, the ONLY workflows were
# main.yml (`on: release`) and publish.yml (`on: workflow_dispatch`) — so nothing
# was built or tested until a release was cut, and a broken tree could sit on
# develop indefinitely. That is exactly how the JDK-21-vs-`--release 25` breakage
# (H15) survived: no build ever ran to notice it.
#
# `next` is listed because it is where development actually lands: master was 127
# commits behind it, so every branch this workflow watched was dormant. The gap was
# not theoretical — BeakGraphQueryCapabilityTest kept calling the 13-argument
# LwsResource constructor after the record gained a 14th component (sha256), and
# that testCompile failure sat on next unnoticed because no workflow built it.
# Any branch developers push to belongs in both lists below.
on:
push:
branches: [ master, next, develop ]
pull_request:
branches: [ master, next, develop ]
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

# Least privilege: this workflow only reads the repo. It needs no token scope,
# and deliberately holds no Maven credentials — it must never publish.
permissions:
contents: read

jobs:
build:
name: mvn verify (JDK 25)
runs-on: ubuntu-latest
# A hung surefire fork would otherwise burn the 6-hour default.
timeout-minutes: 45

steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

# M27/H15: must match <maven.compiler.release> in the root pom. javac cannot
# target a release newer than the JDK running it, and the root pom's
# requireJavaVersion enforcer fails fast if these drift apart.
- name: Set up JDK 25
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
with:
distribution: temurin
java-version: '25'
# M28: cache ~/.m2 so a green build does not re-pull every artifact.
# This is not only speed: the private repo (cursus) answers 403 under
# request pressure, so a cold full download is itself a failure mode.
cache: maven

# The first-party artifacts (BeakGraph, dcm2rdf, cygnus, vandegraph) live on
# the Halcyon repo, which serves them anonymously — no credentials needed to
# BUILD, only to publish. If this step starts failing on 403s for random
# artifacts, that is the rate limiter, not the poms (see M28).
#
# -C (--strict-checksums) fails on a checksum mismatch rather than warning and
# using the artifact anyway, which is Maven's default (M28).
- name: Build and test
run: mvn -B -C -ntp verify

- name: Upload surefire reports
if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: surefire-reports
# Multi-module: reports live under each module's target/, never at the root.
path: '**/target/surefire-reports'
if-no-files-found: warn
retention-days: 7
74 changes: 55 additions & 19 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,42 @@ on:
release:
types: [created]

# L16: least privilege. With no permissions block at all the GITHUB_TOKEN takes the
# repository default, which for repos created before Feb 2023 is write-all — so every
# job, and everything it shells out to (including Maven plugins), held a token that
# could push code rather than merely read it. The three jobs that attach release
# assets raise themselves to contents: write below; nothing else can.
permissions:
contents: read

jobs:
package-ubuntu:
runs-on: ubuntu-latest
permissions:
contents: write # gh release upload
steps:
- name: Checkout code from the repository
uses: actions/checkout@v4
# L16: actions are pinned by commit SHA, not by tag. A tag is mutable —
# whoever controls the action's repository can repoint v4 at new code, which
# would then run here with our GITHUB_TOKEN and our Maven deploy credentials
# already in scope. The trailing comment records the human-readable version
# the SHA was taken from; re-resolve it when bumping.
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

# Set up JDK
# H15: this MUST match <maven.compiler.release> in the root pom (25). javac
# cannot target a release newer than itself, so on JDK 21 every module died with
# "error: release version 25 not supported" and the release pipeline never
# compiled a single class. If the pom's release level moves, move this with it.
- name: Set up JDK
uses: actions/setup-java@v4
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
with:
java-version: '21'
java-version: '25'
distribution: 'temurin'

# Set up the Maven settings (credentials)
- name: Configure Maven settings
uses: s4u/maven-settings-action@v3.0.0
uses: s4u/maven-settings-action@7802f6aec16c9098b4798ad1f1d8ac75198194bd # v3.0.0
with:
servers: |
[{
Expand All @@ -30,14 +49,18 @@ jobs:

# Build and package the Maven project
- name: Build Maven Project
run: mvn -B package --file pom.xml
# M28: -C (--strict-checksums) fails the build on a checksum mismatch instead of
# warning and using the artifact anyway (Maven's default). The <checksumPolicy>
# in the poms covers our own repos; -C additionally covers Maven Central, which
# no pom repository block can configure.
run: mvn -B -C package --file pom.xml

# Deploy to Halcyon Public Maven repository
- name: Deploy with Maven
run: mvn deploy
run: mvn -B -C deploy

- name: Upload JAR
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: halcyon-jar
path: Halcyon/target/Halcyon*.jar
Expand All @@ -48,28 +71,35 @@ jobs:
mvn jpackage:jpackage@ubuntu

- name: '📦 Upload Package'
# L16: the tag reaches the script through env, never through ${{ }}. A
# ${{ ... }} expansion is textual substitution performed BEFORE the shell parses
# the line, so a release tag containing shell metacharacters became commands
# executing with GITHUB_TOKEN in scope. Referenced as "$TAG" it is only data.
run: |
gh release upload ${{github.event.release.tag_name}} Halcyon/target/Halcyon*.jar
gh release upload ${{github.event.release.tag_name}} Halcyon/dist/halcyon*.deb
gh release upload "$TAG" Halcyon/target/Halcyon*.jar
gh release upload "$TAG" Halcyon/dist/halcyon*.deb
env:
GITHUB_TOKEN: ${{ github.TOKEN }}
TAG: ${{ github.event.release.tag_name }}
shell: bash

package-mac:
needs: package-ubuntu
runs-on: macos-latest
permissions:
contents: write # gh release upload
steps:
- name: Checkout main branch from GitHub
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

- name: Set up JDK for Mac
uses: actions/setup-java@v4
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
with:
java-version: '21'
java-version: '25'
distribution: 'temurin'

- name: Download JAR
uses: actions/download-artifact@v4
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: halcyon-jar
path: Halcyon/target
Expand All @@ -80,25 +110,29 @@ jobs:
mvn jpackage:jpackage@mac

- name: '📦 Upload macOS Package'
run: gh release upload ${{github.event.release.tag_name}} Halcyon/dist/Halcyon*.dmg
run: gh release upload "$TAG" Halcyon/dist/Halcyon*.dmg
env:
GITHUB_TOKEN: ${{ github.TOKEN }}
TAG: ${{ github.event.release.tag_name }}
shell: bash

package-windows:
needs: package-ubuntu
runs-on: windows-latest
permissions:
contents: write # gh release upload
steps:
- name: Checkout main branch from GitHub
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

- name: Set up JDK for Windows
uses: actions/setup-java@v4
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
with:
java-version: '21'
java-version: '25'
distribution: 'temurin'

- name: Download JAR
uses: actions/download-artifact@v4
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: halcyon-jar
path: Halcyon\target
Expand All @@ -109,11 +143,13 @@ jobs:
mvn jpackage:jpackage@win

- name: '📦 Upload Windows Package'
# $env:TAG for the same reason as the bash jobs above.
run: |
$files = Get-ChildItem Halcyon\dist\Halcyon*.msi
foreach ($file in $files) {
gh release upload ${{github.event.release.tag_name}} $file.FullName
gh release upload $env:TAG $file.FullName
}
shell: pwsh
env:
GITHUB_TOKEN: ${{ github.TOKEN }}
TAG: ${{ github.event.release.tag_name }}
19 changes: 13 additions & 6 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,29 @@ name: Publish project to Maven repository
# Trigger workflow manually
on: workflow_dispatch

# L16: this job only reads the repo — it publishes to the Maven server using
# MAVEN_NAME/MAVEN_SECRET, not the GITHUB_TOKEN — so the token gets read-only.
permissions:
contents: read

jobs:
publish:
runs-on: ubuntu-latest
steps:
# Checkout code from the repository
- uses: actions/checkout@v4
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

# Set up JDK
# H15: must match <maven.compiler.release> in the root pom (25) — see main.yml.
- name: Set up JDK
uses: actions/setup-java@v4
uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0
with:
java-version: '21'
java-version: '25'
distribution: 'temurin'

# Set up the Maven settings (credentials)
- name: Configure Maven settings
uses: s4u/maven-settings-action@v3.0.0
uses: s4u/maven-settings-action@7802f6aec16c9098b4798ad1f1d8ac75198194bd # v3.0.0
with:
servers: |
[{
Expand All @@ -29,8 +35,9 @@ jobs:

# Build and package the Maven project
- name: Build Maven Project
run: mvn -B package --file pom.xml
# M28: -C = --strict-checksums (see main.yml).
run: mvn -B -C package --file pom.xml

# Deploy to the repository
- name: Deploy with Maven
run: mvn deploy
run: mvn -B -C deploy
Loading
Loading