Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8f28406
feat: ETU-68417: Testing new auth solution between GHA and new publis…
rikard-swahn Feb 16, 2026
0a9cbe2
feat: ETU-68417: Testing new auth solution between GHA and new publis…
rikard-swahn Feb 16, 2026
ece2a87
feat: ETU-68417: Uploading each spec to cloud run function
rikard-swahn Feb 17, 2026
476dff8
fix: ETU-68417: Removed invalid path "/specs"
rikard-swahn Feb 17, 2026
d2141a0
fix: ETU-68417: Removed the "visibility" input in the publish workflo…
rikard-swahn Feb 25, 2026
2cf5719
docs: Update workflow documentation
rikard-swahn Feb 25, 2026
4104eb5
fix: ETU-68417: Using prd cloud function
rikard-swahn Feb 25, 2026
19154f9
Merge remote-tracking branch 'origin/ETU-68417-publish-auth' into ETU…
rikard-swahn Feb 25, 2026
c478eb7
fix: ETU-68417: Testing spec update
rikard-swahn Feb 25, 2026
d75b53d
Revert "fix: ETU-68417: Testing spec update"
rikard-swahn Feb 25, 2026
9fe2ff5
fix: ETU-68417: Not uploading to spec reg in test
rikard-swahn Feb 25, 2026
3dec4ed
fix: ETU-68417: Setting ${{ steps.auth.outputs.id_token }} in env var…
rikard-swahn Feb 25, 2026
b63aeb6
fix: ETU-68417: test
rikard-swahn Feb 25, 2026
12a4409
Potential fix for code scanning alert no. 36: Code injection
rikard-swahn Feb 25, 2026
45266bf
fix: ETU-68417: Renamed job "call-publish-endpoint" -> "upload"
rikard-swahn Feb 25, 2026
f38d749
Merge remote-tracking branch 'origin/ETU-68417-publish-auth' into ETU…
rikard-swahn Feb 25, 2026
a17a530
Revert "fix: ETU-68417: test"
rikard-swahn Feb 25, 2026
8288ae0
Reapply "fix: ETU-68417: test"
rikard-swahn Feb 27, 2026
f5a6e4a
fix: ETU-68417: Using dev function, for testing
rikard-swahn Feb 27, 2026
412da50
Revert "fix: ETU-68417: Using dev function, for testing"
rikard-swahn Feb 27, 2026
e5d85ff
Revert "Reapply "fix: ETU-68417: test""
rikard-swahn Feb 27, 2026
79623b8
fix: ETU-68417: PUT:ing spec instead of POST:ing
rikard-swahn Feb 27, 2026
ba4783d
Reapply "Reapply "fix: ETU-68417: test""
rikard-swahn Mar 2, 2026
4a45c1d
fix: ETU-68417: Testing publish
rikard-swahn Mar 2, 2026
8be87da
fix: ETU-68417: Testing publish
rikard-swahn Mar 2, 2026
65863cf
fix: ETU-68417: Testing publish
rikard-swahn Mar 2, 2026
70c9020
Revert "fix: ETU-68417: Testing publish"
rikard-swahn Mar 2, 2026
2756421
Revert "fix: ETU-68417: Testing publish"
rikard-swahn Mar 2, 2026
2c61eef
Revert "fix: ETU-68417: Testing publish"
rikard-swahn Mar 2, 2026
e66b53a
Revert "Reapply "Reapply "fix: ETU-68417: test"""
rikard-swahn Mar 2, 2026
7b331d0
feat: Improve inputs
egrimstad Mar 3, 2026
a0e1c6c
docs: Update workflow documentation
egrimstad Mar 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
Reusable GitHub Actions to help Entur teams:

- Lint OpenAPI specs with Spectral
- Publish OpenAPI specs to the developer portal storage (with visibility control)
- Publish OpenAPI specs to the developer portal storage

## Get started

Expand Down
149 changes: 52 additions & 97 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,62 +1,20 @@
name: Publish OpenAPI specs to developer portal
name: Publish OpenAPI spec to developer portal

on:
workflow_call:
inputs:
spec:
description: "OpenAPI specs to publish, as a glob pattern."
type: string
default: "specs/*.json"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

specs/openapi.json

artifact:
description: "OpenAPI specs to publish, as a GitHub artifact glob pattern."
type: string
artifact_contents:
description: "Glob pattern inside artifacts to include in publishing, only used if artifact is provided."
description: "Artifact where OpenAPI spec is located."
type: string
default: "*"
visibility:
description: "Visibility of the published specs. Can be 'public', 'partner' or 'internal'."
path:
required: true
description: "Path to OpenAPI spec"
type: string
default: "public"

jobs:
validate-input:
name: Validate input
if: ${{ github.actor != 'dependabot[bot]' }}
runs-on: ubuntu-latest
steps:
- name: Validate inputs
env:
GHA_API_SPEC: ${{ inputs.spec }}
GHA_API_ARTIFACT: ${{ inputs.artifact }}
GHA_API_VISIBILITY: ${{ inputs.visibility }}
run: |
set -o errexit #Exits immediately if any command fails (returns non-zero)
set -o nounset #Treats unset variables as errors
set -o pipefail #Makes a pipeline fail if any command in it fails (not just the last)

# Ensure not both inputs are empty.
if [ -z "$GHA_API_ARTIFACT" ] && [ -z "$GHA_API_SPEC" ]; then
echo "::error::Exactly one of spec OR artifact is required."
exit 1
fi

# Ensure not both inputs are provided.
if [ -n "$GHA_API_ARTIFACT" ] && [ -n "$GHA_API_SPEC" ] && [ "$GHA_API_SPEC" != "specs/*.json" ]; then
echo "::error::Both spec and artifact were provided. Please provide only one."
exit 1
fi

# Ensure visibility is valid
if [[ ! "$GHA_API_VISIBILITY" =~ ^(public|partner|internal)$ ]]; then
echo "::error::Invalid visibility '$GHA_API_VISIBILITY'. Must be one of: public, partner, internal."
exit 1
fi

validate-spec:
name: Validate Spec
name: Validate spec
runs-on: ubuntu-latest
needs: validate-input
permissions:
contents: read
steps:
Expand All @@ -67,9 +25,8 @@ jobs:
if: ${{ inputs.artifact != '' }}
uses: actions/download-artifact@v7
with:
pattern: ${{ inputs.artifact }}
path: /tmp/artifacts
merge-multiple: true
name: ${{ inputs.artifact }}
path: /tmp/artifact
- name: Checkout linting rulesets
uses: actions/checkout@v6
with:
Expand All @@ -85,32 +42,33 @@ jobs:
shell: bash
env:
GHA_API_ARTIFACT: ${{ inputs.artifact }}
GHA_API_SPEC: ${{ inputs.spec }}
GHA_API_CONTENTS: ${{ inputs.artifact_contents }}
GHA_API_PATH: ${{ inputs.path }}
run: |
set -o errexit
set -o nounset
set -o pipefail
shopt -s globstar

if [ -n "$GHA_API_ARTIFACT" ]; then
spec_glob="/tmp/artifacts/$GHA_API_CONTENTS"
spec_path="/tmp/artifact/$GHA_API_PATH"
else
spec_glob="$GHA_API_SPEC"
spec_path="$GHA_API_PATH"
fi

if ! spectral lint "$spec_glob" --ruleset "rulesets/.spectral-required.yml"; then
if ! spectral lint "$spec_path" --ruleset "rulesets/.spectral-required.yml"; then
echo "::error::Spec validation failed. Failing workflow."
exit 1
fi

upload-to-bucket:
name: Upload to bucket
upload:
name: Upload spec
needs: validate-spec
permissions:
contents: read
id-token: write
runs-on: ubuntu-latest
env:
CLOUD_RUN_ENDPOINT: https://europe-west1-ent-apidata-prd.cloudfunctions.net/publish-spec
steps:
- name: Checkout repository (if spec provided)
if: ${{ inputs.artifact == '' }}
Expand All @@ -119,56 +77,53 @@ jobs:
if: ${{ inputs.artifact != '' }}
uses: actions/download-artifact@v7
with:
pattern: ${{ inputs.artifact }}
path: /tmp/artifacts
merge-multiple: true
- name: Check ENTUR_API_DATA_SA secret exists
env:
ENTUR_API_DATA_SA: ${{ secrets.ENTUR_API_DATA_SA }}
REPO_VISIBILITY: ${{ github.event.repository.visibility }}
run: |
if [ -z "$ENTUR_API_DATA_SA" ]; then
if [ "$REPO_VISIBILITY" = "public" ]; then
echo "::error::Upload to bucket will not work out of the box for public repositories, due to the \
repository secret ENTUR_API_DATA_SA not being available. Ask Team Plattform to add it."
else
echo "::error::The repository secret ENTUR_API_DATA_SA is not available. Please ensure it is configured."
fi
exit 1
fi
name: ${{ inputs.artifact }}
path: /tmp/artifact

- name: Authenticate with Google Cloud
id: auth
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
with:
credentials_json: "${{ secrets.ENTUR_API_DATA_SA }}"
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1
- name: Copy specs to temporary directory
workload_identity_provider: ${{ vars.CI_WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ vars.CI_SERVICE_ACCOUNT }}
token_format: id_token
id_token_audience: ${{ env.CLOUD_RUN_ENDPOINT }}
id_token_include_email: true
create_credentials_file: false

- name: Publish spec
env:
GHA_API_ARTIFACT: ${{ inputs.artifact }}
GHA_API_SPEC: ${{ inputs.spec }}
GHA_API_CONTENTS: ${{ inputs.artifact_contents }}
GHA_API_VISIBILITY: ${{ inputs.visibility }}

GHA_API_PATH: ${{ inputs.path }}
ID_TOKEN: ${{ steps.auth.outputs.id_token }}
CLOUD_RUN_ENDPOINT: ${{ env.CLOUD_RUN_ENDPOINT }}
run: |
set -o errexit
set -o nounset
set -o pipefail
shopt -s globstar

mkdir -p /tmp/specs

# Determine spec glob pattern based on input type
if [ -z "$GHA_API_ARTIFACT" ]; then
cp $GHA_API_SPEC /tmp/specs
spec_path="$GHA_API_PATH"
else
#Since gcloud storage rsync does not support GLOB, copy files matching artifact_contents to /tmp/specs for upload
cp /tmp/artifacts/$GHA_API_CONTENTS /tmp/specs
spec_path="/tmp/artifacts/$GHA_API_PATH"
fi
- name: Upload specs to GCS
env:
GHA_API_VISIBILITY: ${{ inputs.visibility }}
run: |
set -o errexit
set -o nounset
set -o pipefail
echo "Starting to sync files in /tmp/specs/ to GCS Bucket to path /${GHA_API_VISIBILITY}/${GITHUB_REPOSITORY#*/}"
gcloud storage rsync /tmp/specs/ "gs://ent-gcs-api-specs-developer-portal-prd-001/${GHA_API_VISIBILITY}/${GITHUB_REPOSITORY#*/}"

# Extract repository name (without owner)
REPO_NAME="${GITHUB_REPOSITORY#*/}"

# Create metadata JSON
METADATA="{\"repository\": \"$REPO_NAME\"}"

# Iterate through all matching spec files and PUT them
echo "Publishing spec: $spec_path"

curl --fail-with-body -sS \
-X PUT \
-H "Authorization: Bearer $ID_TOKEN" \
-F "metadata=$METADATA;type=application/json" \
-F "spec=@$spec_path" \
"$CLOUD_RUN_ENDPOINT"

echo "Successfully published: $spec_path"
33 changes: 5 additions & 28 deletions README-publish.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@

<!-- AUTO-DOC-INPUT:START - Do not remove or modify this section -->

| INPUT | TYPE | REQUIRED | DEFAULT | DESCRIPTION |
|-------------------------------------------------------------------------------------|--------|----------|------------------|-----------------------------------------------------------------------------------------------------|
| <a name="input_artifact"></a>[artifact](#input_artifact) | string | false | | OpenAPI specs to publish, as <br>a GitHub artifact glob pattern. |
| <a name="input_artifact_contents"></a>[artifact_contents](#input_artifact_contents) | string | false | `"*"` | Glob pattern inside artifacts to <br>include in publishing, only used <br>if artifact is provided. |
| <a name="input_spec"></a>[spec](#input_spec) | string | false | `"specs/*.json"` | OpenAPI specs to publish, as <br>a glob pattern. |
| <a name="input_visibility"></a>[visibility](#input_visibility) | string | false | `"public"` | Visibility of the published specs. <br>Can be 'public', 'partner' or <br>'internal'. |
| INPUT | TYPE | REQUIRED | DEFAULT | DESCRIPTION |
|----------------------------------------------------------|--------|----------|---------|----------------------------------------------|
| <a name="input_artifact"></a>[artifact](#input_artifact) | string | false | | Artifact where OpenAPI spec is <br>located. |
| <a name="input_path"></a>[path](#input_path) | string | true | | Path to OpenAPI spec |

<!-- AUTO-DOC-INPUT:END -->

Expand Down Expand Up @@ -76,25 +74,4 @@ jobs:
with:
artifact: myArtifactName
artifact_contents: "*.yaml"
```

## Specifying visibility of API

By default, your API will be publicly available, if you wish to change the visibility of your API spec, set visibility to one of

- public (default)
- partner
- internal

```yml
jobs:
openapi-publish:
#[...]
with:
visibility: internal
```

### For public repositories

This reusable workflow will not work out of the box for public repositories, due to the secret `ENTUR_API_DATA_SA` not being available.
For these repositories, you must ask team plattform to manually add `ENTUR_API_DATA_SA` as a repository secret.
```