wip: inital set of shared actions
This commit is contained in:
parent
553786f000
commit
a09a422251
39 changed files with 1775 additions and 51 deletions
44
.github/actions/aikido-full-scan/README.md
vendored
Normal file
44
.github/actions/aikido-full-scan/README.md
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# aikido-full-scan
|
||||
|
||||
Run a full Aikido security scan — intended for nightly or scheduled runs.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `aikido-api-key` | Yes | | Aikido CI API key (`AIK_CI_xxx`) |
|
||||
| `branch-name` | Yes | | Branch to scan (`dev` for applications, `main` for libraries) |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/aikido-full-scan@v1
|
||||
with:
|
||||
aikido-api-key: ${{ secrets.AIKIDO_API_KEY }}
|
||||
branch-name: dev
|
||||
```
|
||||
|
||||
### Nightly schedule example
|
||||
|
||||
```yaml
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * *'
|
||||
|
||||
jobs:
|
||||
aikido-scan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: schmalz/shared-actions/.github/actions/aikido-full-scan@v1
|
||||
with:
|
||||
aikido-api-key: ${{ secrets.AIKIDO_API_KEY }}
|
||||
branch-name: dev
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Uses the `aikidosecurity/local-scanner` Docker image to scan inside the CI runner.
|
||||
- Performs a full scan (all scan types: code, dependencies, IaC, secrets) and uploads results to the Aikido dashboard.
|
||||
- Repository name is auto-detected from Forgejo environment variables.
|
||||
- Does not run in gating mode — the scan reports findings but does not fail the workflow unless the scanner itself errors.
|
||||
29
.github/actions/aikido-full-scan/action.yml
vendored
Normal file
29
.github/actions/aikido-full-scan/action.yml
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
name: aikido-full-scan
|
||||
description: Run a full Aikido security scan (for nightly/scheduled runs)
|
||||
|
||||
inputs:
|
||||
aikido-api-key:
|
||||
description: 'Aikido CI API key (AIK_CI_xxx)'
|
||||
required: true
|
||||
branch-name:
|
||||
description: 'Branch to scan (e.g., dev for applications, main for libraries)'
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Aikido full scan
|
||||
shell: bash
|
||||
env:
|
||||
AIKIDO_API_KEY: ${{ inputs.aikido-api-key }}
|
||||
INPUT_BRANCH_NAME: ${{ inputs.branch-name }}
|
||||
run: |
|
||||
REPO_NAME="${GITHUB_REPOSITORY##*/}"
|
||||
|
||||
docker run --rm \
|
||||
-v "$GITHUB_WORKSPACE:/repo" \
|
||||
-e AIKIDO_API_KEY \
|
||||
aikidosecurity/local-scanner:latest \
|
||||
scan /repo \
|
||||
--repositoryname "$REPO_NAME" \
|
||||
--branchname "$INPUT_BRANCH_NAME"
|
||||
26
.github/actions/aikido-pr-scan/README.md
vendored
Normal file
26
.github/actions/aikido-pr-scan/README.md
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# aikido-pr-scan
|
||||
|
||||
Run Aikido security scan on a PR in gating mode — fails if new vulnerabilities are introduced.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `aikido-api-key` | Yes | | Aikido CI API key (`AIK_CI_xxx`) |
|
||||
| `fail-on` | No | `high` | Minimum severity to fail on (`low`, `medium`, `high`, `critical`) |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/aikido-pr-scan@v1
|
||||
with:
|
||||
aikido-api-key: ${{ secrets.AIKIDO_API_KEY }}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Uses the `aikidosecurity/local-scanner` Docker image to scan inside the CI runner.
|
||||
- Runs in PR gating mode: only detects **new** vulnerabilities introduced by the PR (diff-based).
|
||||
- Repository name and branch are auto-detected from Forgejo environment variables.
|
||||
- The API key is passed via environment variable, never interpolated in shell commands.
|
||||
- Base and head commit IDs are derived from `GITHUB_BASE_SHA` and `GITHUB_SHA`.
|
||||
37
.github/actions/aikido-pr-scan/action.yml
vendored
Normal file
37
.github/actions/aikido-pr-scan/action.yml
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
name: aikido-pr-scan
|
||||
description: Run Aikido security scan on a PR in gating mode (fails on new vulnerabilities)
|
||||
|
||||
inputs:
|
||||
aikido-api-key:
|
||||
description: 'Aikido CI API key (AIK_CI_xxx)'
|
||||
required: true
|
||||
fail-on:
|
||||
description: 'Minimum severity to fail on (low, medium, high, critical)'
|
||||
required: false
|
||||
default: 'high'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Aikido PR scan
|
||||
shell: bash
|
||||
env:
|
||||
AIKIDO_API_KEY: ${{ inputs.aikido-api-key }}
|
||||
INPUT_FAIL_ON: ${{ inputs.fail-on }}
|
||||
run: |
|
||||
REPO_NAME="${GITHUB_REPOSITORY##*/}"
|
||||
BRANCH_NAME="${GITHUB_HEAD_REF}"
|
||||
BASE_COMMIT="${GITHUB_BASE_SHA:-$(git rev-parse HEAD~1)}"
|
||||
HEAD_COMMIT="${GITHUB_SHA}"
|
||||
|
||||
docker run --rm \
|
||||
-v "$GITHUB_WORKSPACE:/repo" \
|
||||
-e AIKIDO_API_KEY \
|
||||
aikidosecurity/local-scanner:latest \
|
||||
scan /repo \
|
||||
--repositoryname "$REPO_NAME" \
|
||||
--branchname "$BRANCH_NAME" \
|
||||
--gating-mode pr \
|
||||
--fail-on "$INPUT_FAIL_ON" \
|
||||
--base-commit-id "$BASE_COMMIT" \
|
||||
--head-commit-id "$HEAD_COMMIT"
|
||||
25
.github/actions/aws-configure/README.md
vendored
Normal file
25
.github/actions/aws-configure/README.md
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# aws-configure
|
||||
|
||||
Authenticate with AWS via OIDC and export credentials to the environment.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `role-arn` | Yes | | Full IAM role ARN |
|
||||
| `aws-profile` | No | `default` | Profile name written to `~/.aws/config` |
|
||||
| `region` | No | `eu-central-1` | AWS region |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/aws-configure@v1
|
||||
with:
|
||||
role-arn: arn:aws:iam::123456789012:role/my-role
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Requires `enable-openid-connect: true` on the Forgejo runner job.
|
||||
- Credentials are exported via `$FORGEJO_ENV` so subsequent steps can use them.
|
||||
- When `aws-profile` is not `default`, a named AWS CLI profile is also configured.
|
||||
45
.github/actions/aws-configure/action.yml
vendored
Normal file
45
.github/actions/aws-configure/action.yml
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
name: aws-configure
|
||||
description: Authenticate with AWS via OIDC
|
||||
|
||||
inputs:
|
||||
role-arn:
|
||||
description: Full IAM role ARN
|
||||
required: true
|
||||
aws-profile:
|
||||
description: Profile name written to ~/.aws/config
|
||||
required: false
|
||||
default: default
|
||||
region:
|
||||
description: AWS region
|
||||
required: false
|
||||
default: eu-central-1
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- run: |
|
||||
OIDC_TOKEN=$(curl -sf \
|
||||
-H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
|
||||
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=sts.amazonaws.com" | jq -r .value)
|
||||
|
||||
CREDS=$(aws sts assume-role-with-web-identity \
|
||||
--role-arn "$INPUT_ROLE_ARN" \
|
||||
--role-session-name forgejo-ci \
|
||||
--web-identity-token "$OIDC_TOKEN" \
|
||||
--region "$INPUT_REGION" \
|
||||
--query 'Credentials' --output json)
|
||||
|
||||
mkdir -p ~/.aws
|
||||
|
||||
echo "AWS_ACCESS_KEY_ID=$(echo $CREDS | jq -r .AccessKeyId)" >> $FORGEJO_ENV
|
||||
echo "AWS_SECRET_ACCESS_KEY=$(echo $CREDS | jq -r .SecretAccessKey)" >> $FORGEJO_ENV
|
||||
echo "AWS_SESSION_TOKEN=$(echo $CREDS | jq -r .SessionToken)" >> $FORGEJO_ENV
|
||||
echo "AWS_DEFAULT_REGION=$INPUT_REGION" >> $FORGEJO_ENV
|
||||
|
||||
if [ "$INPUT_AWS_PROFILE" != "default" ]; then
|
||||
aws configure set aws_access_key_id "$(echo $CREDS | jq -r .AccessKeyId)" --profile "$INPUT_AWS_PROFILE"
|
||||
aws configure set aws_secret_access_key "$(echo $CREDS | jq -r .SecretAccessKey)" --profile "$INPUT_AWS_PROFILE"
|
||||
aws configure set aws_session_token "$(echo $CREDS | jq -r .SessionToken)" --profile "$INPUT_AWS_PROFILE"
|
||||
aws configure set region "$INPUT_REGION" --profile "$INPUT_AWS_PROFILE"
|
||||
fi
|
||||
shell: bash
|
||||
50
.github/actions/aws-lambda-update/README.md
vendored
Normal file
50
.github/actions/aws-lambda-update/README.md
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# aws-lambda-update
|
||||
|
||||
Update Lambda function alias to a new version, optionally wait for provisioned concurrency.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `function-name` | Yes | | Lambda function name |
|
||||
| `function-version` | Yes | | Lambda version number |
|
||||
| `alias-name` | Yes | | Alias name |
|
||||
| `aws-role-arn` | Yes | | IAM role via OIDC |
|
||||
| `wait-provisioned-concurrency` | No | `false` | Poll until provisioned concurrency is READY |
|
||||
| `aws-profile` | No | `default` | AWS CLI profile name |
|
||||
| `region` | No | `eu-central-1` | AWS region |
|
||||
| `lambda-alias-updates-json` | No | `""` | JSON array of `{function_name, version, alias_name}` objects for batch updates |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/aws-lambda-update@v1
|
||||
with:
|
||||
function-name: my-function
|
||||
function-version: "42"
|
||||
alias-name: live
|
||||
aws-role-arn: ${{ secrets.AWS_ROLE_ARN }}
|
||||
wait-provisioned-concurrency: "true"
|
||||
```
|
||||
|
||||
### Batch update
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/aws-lambda-update@v1
|
||||
with:
|
||||
function-name: unused
|
||||
function-version: "0"
|
||||
alias-name: unused
|
||||
aws-role-arn: ${{ secrets.AWS_ROLE_ARN }}
|
||||
lambda-alias-updates-json: |
|
||||
[
|
||||
{"function_name": "fn-a", "version": "3", "alias_name": "live"},
|
||||
{"function_name": "fn-b", "version": "7", "alias_name": "live"}
|
||||
]
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- When `lambda-alias-updates-json` is set, the single-alias inputs (`function-name`, `function-version`, `alias-name`) are ignored.
|
||||
- Provisioned concurrency polling checks every 5 seconds and fails the step if status becomes `FAILED`.
|
||||
- Uses `aws-configure` internally for OIDC authentication.
|
||||
95
.github/actions/aws-lambda-update/action.yml
vendored
Normal file
95
.github/actions/aws-lambda-update/action.yml
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
name: aws-lambda-update
|
||||
description: Update Lambda function alias to a new version, optionally wait for provisioned concurrency
|
||||
|
||||
inputs:
|
||||
function-name:
|
||||
description: Lambda function name
|
||||
required: true
|
||||
function-version:
|
||||
description: Lambda version number
|
||||
required: true
|
||||
alias-name:
|
||||
description: Alias name
|
||||
required: true
|
||||
wait-provisioned-concurrency:
|
||||
description: Poll until provisioned concurrency is READY
|
||||
required: false
|
||||
default: "false"
|
||||
aws-role-arn:
|
||||
description: IAM role via OIDC
|
||||
required: true
|
||||
aws-profile:
|
||||
description: AWS CLI profile name
|
||||
required: false
|
||||
default: default
|
||||
region:
|
||||
description: AWS region
|
||||
required: false
|
||||
default: eu-central-1
|
||||
lambda-alias-updates-json:
|
||||
description: JSON array of {function_name, version, alias_name} objects; when set, applies all entries instead of single alias
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: schmalz/shared-actions/.github/actions/aws-configure@v1
|
||||
with:
|
||||
role-arn: ${{ inputs.aws-role-arn }}
|
||||
aws-profile: ${{ inputs.aws-profile }}
|
||||
region: ${{ inputs.region }}
|
||||
|
||||
- run: |
|
||||
AWS_PROFILE="${{ inputs.aws-profile }}"
|
||||
WAIT_PC="${{ inputs.wait-provisioned-concurrency }}"
|
||||
|
||||
update_alias() {
|
||||
local fn="$1" ver="$2" alias="$3"
|
||||
echo "Updating alias '$alias' on '$fn' to version $ver"
|
||||
aws lambda update-alias \
|
||||
--function-name "$fn" \
|
||||
--name "$alias" \
|
||||
--function-version "$ver" \
|
||||
--profile "$AWS_PROFILE"
|
||||
}
|
||||
|
||||
wait_provisioned_concurrency() {
|
||||
local fn="$1" alias="$2"
|
||||
echo "Waiting for provisioned concurrency on '$fn' alias '$alias'..."
|
||||
while true; do
|
||||
STATUS=$(aws lambda get-provisioned-concurrency-config \
|
||||
--function-name "$fn" \
|
||||
--qualifier "$alias" \
|
||||
--profile "$AWS_PROFILE" \
|
||||
--query 'Status' --output text 2>/dev/null || echo "NOT_FOUND")
|
||||
echo " Status: $STATUS"
|
||||
if [ "$STATUS" = "READY" ]; then
|
||||
break
|
||||
elif [ "$STATUS" = "FAILED" ]; then
|
||||
echo "ERROR: Provisioned concurrency failed for '$fn' alias '$alias'"
|
||||
exit 1
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
}
|
||||
|
||||
UPDATES_JSON='${{ inputs.lambda-alias-updates-json }}'
|
||||
|
||||
if [ -n "$UPDATES_JSON" ]; then
|
||||
echo "$UPDATES_JSON" | jq -c '.[]' | while read -r entry; do
|
||||
FN=$(echo "$entry" | jq -r '.function_name')
|
||||
VER=$(echo "$entry" | jq -r '.version')
|
||||
ALIAS=$(echo "$entry" | jq -r '.alias_name')
|
||||
update_alias "$FN" "$VER" "$ALIAS"
|
||||
if [ "$WAIT_PC" = "true" ]; then
|
||||
wait_provisioned_concurrency "$FN" "$ALIAS"
|
||||
fi
|
||||
done
|
||||
else
|
||||
update_alias "${{ inputs.function-name }}" "${{ inputs.function-version }}" "${{ inputs.alias-name }}"
|
||||
if [ "$WAIT_PC" = "true" ]; then
|
||||
wait_provisioned_concurrency "${{ inputs.function-name }}" "${{ inputs.alias-name }}"
|
||||
fi
|
||||
fi
|
||||
shell: bash
|
||||
31
.github/actions/aws-s3-sync/README.md
vendored
Normal file
31
.github/actions/aws-s3-sync/README.md
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# aws-s3-sync
|
||||
|
||||
Sync build artifacts to S3, clean up old versioned assets, and optionally invalidate CloudFront.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `source-dir` | Yes | | Local path to sync |
|
||||
| `s3-bucket` | Yes | | Target S3 bucket name |
|
||||
| `aws-role-arn` | Yes | | IAM role ARN for OIDC authentication |
|
||||
| `cache-control` | No | `public, max-age=31536000, immutable` | HTTP `Cache-Control` header |
|
||||
| `aws-profile` | No | `default` | AWS CLI profile name |
|
||||
| `cloudfront-distribution-ids-file` | No | `""` | Path to file with space-separated CloudFront distribution IDs |
|
||||
| `retention-days` | No | `7` | Delete `_static/<timestamp>` prefixes older than this many days (`0` to skip) |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/aws-s3-sync@v1
|
||||
with:
|
||||
source-dir: dist/
|
||||
s3-bucket: my-app-bucket
|
||||
aws-role-arn: arn:aws:iam::123456789012:role/my-role
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Requires `enable-openid-connect: true` on the job.
|
||||
- Old assets under `_static/` are cleaned up based on `retention-days` by parsing timestamp-named prefixes.
|
||||
- CloudFront invalidation uses `/*` path and is triggered only when `cloudfront-distribution-ids-file` points to an existing file.
|
||||
71
.github/actions/aws-s3-sync/action.yml
vendored
Normal file
71
.github/actions/aws-s3-sync/action.yml
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
name: aws-s3-sync
|
||||
description: Sync build artifacts to S3, clean up old versioned assets, optionally invalidate CloudFront
|
||||
|
||||
inputs:
|
||||
source-dir:
|
||||
description: Local path to sync
|
||||
required: true
|
||||
s3-bucket:
|
||||
description: Target S3 bucket name
|
||||
required: true
|
||||
cache-control:
|
||||
description: HTTP Cache-Control header
|
||||
required: false
|
||||
default: "public, max-age=31536000, immutable"
|
||||
aws-role-arn:
|
||||
description: IAM role via OIDC
|
||||
required: true
|
||||
aws-profile:
|
||||
description: AWS CLI profile name
|
||||
required: false
|
||||
default: default
|
||||
cloudfront-distribution-ids-file:
|
||||
description: Path to file with space-separated CF distribution IDs. If set, creates invalidations.
|
||||
required: false
|
||||
default: ""
|
||||
retention-days:
|
||||
description: Delete versioned _static/<timestamp> prefixes older than this many days (0 = skip)
|
||||
required: false
|
||||
default: "7"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: schmalz/shared-actions/.github/actions/aws-configure@v1
|
||||
with:
|
||||
role-arn: ${{ inputs.aws-role-arn }}
|
||||
aws-profile: ${{ inputs.aws-profile }}
|
||||
|
||||
- run: |
|
||||
SOURCE_DIR="${{ inputs.source-dir }}"
|
||||
S3_BUCKET="${{ inputs.s3-bucket }}"
|
||||
CACHE_CONTROL="${{ inputs.cache-control }}"
|
||||
AWS_PROFILE="${{ inputs.aws-profile }}"
|
||||
RETENTION_DAYS="${{ inputs.retention-days }}"
|
||||
CF_IDS_FILE="${{ inputs.cloudfront-distribution-ids-file }}"
|
||||
|
||||
# Sync
|
||||
aws s3 sync "$SOURCE_DIR" "s3://$S3_BUCKET" \
|
||||
--cache-control "$CACHE_CONTROL" \
|
||||
--profile "$AWS_PROFILE"
|
||||
|
||||
# Cleanup old _static/ prefixes if retention-days > 0
|
||||
if [ "$RETENTION_DAYS" -gt 0 ]; then
|
||||
CUTOFF=$(date -d "-${RETENTION_DAYS} days" +%s)
|
||||
aws s3 ls "s3://$S3_BUCKET/_static/" --profile "$AWS_PROFILE" | while read -r line; do
|
||||
PREFIX=$(echo "$line" | awk '{print $2}')
|
||||
# Extract timestamp from prefix name, compare to cutoff, delete if old
|
||||
TIMESTAMP=$(echo "$PREFIX" | tr -d '/')
|
||||
if [ $(date -d "$TIMESTAMP" +%s 2>/dev/null || echo 0) -lt "$CUTOFF" ]; then
|
||||
aws s3 rm "s3://$S3_BUCKET/_static/$PREFIX" --recursive --profile "$AWS_PROFILE"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# CloudFront invalidation
|
||||
if [ -n "$CF_IDS_FILE" ] && [ -f "$CF_IDS_FILE" ]; then
|
||||
for DIST_ID in $(cat "$CF_IDS_FILE"); do
|
||||
aws cloudfront create-invalidation --distribution-id "$DIST_ID" --paths "/*" --profile "$AWS_PROFILE"
|
||||
done
|
||||
fi
|
||||
shell: bash
|
||||
27
.github/actions/cloudfront-invalidate/README.md
vendored
Normal file
27
.github/actions/cloudfront-invalidate/README.md
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# cloudfront-invalidate
|
||||
|
||||
Invalidate one or more CloudFront distributions.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `distribution-ids` | Yes | | Space-separated CloudFront distribution IDs, or path to a file containing them |
|
||||
| `aws-role-arn` | Yes | | IAM role via OIDC |
|
||||
| `paths` | No | `/*` | Invalidation paths |
|
||||
| `aws-profile` | No | `default` | AWS CLI profile name |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/cloudfront-invalidate@v1
|
||||
with:
|
||||
distribution-ids: E1234567890ABC E0987654321XYZ
|
||||
aws-role-arn: ${{ secrets.AWS_ROLE_ARN }}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `distribution-ids` can be literal IDs or a path to a file containing them (one per line or space-separated).
|
||||
- Each distribution is invalidated separately in a loop.
|
||||
- Uses `aws-configure` internally for OIDC authentication.
|
||||
46
.github/actions/cloudfront-invalidate/action.yml
vendored
Normal file
46
.github/actions/cloudfront-invalidate/action.yml
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
name: cloudfront-invalidate
|
||||
description: Invalidate one or more CloudFront distributions
|
||||
|
||||
inputs:
|
||||
distribution-ids:
|
||||
description: Space-separated CloudFront distribution IDs, or path to file containing them
|
||||
required: true
|
||||
paths:
|
||||
description: Invalidation paths
|
||||
required: false
|
||||
default: "/*"
|
||||
aws-role-arn:
|
||||
description: IAM role via OIDC
|
||||
required: true
|
||||
aws-profile:
|
||||
description: AWS CLI profile name
|
||||
required: false
|
||||
default: default
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: schmalz/shared-actions/.github/actions/aws-configure@v1
|
||||
with:
|
||||
role-arn: ${{ inputs.aws-role-arn }}
|
||||
aws-profile: ${{ inputs.aws-profile }}
|
||||
|
||||
- run: |
|
||||
DISTRIBUTION_IDS="${{ inputs.distribution-ids }}"
|
||||
PATHS="${{ inputs.paths }}"
|
||||
AWS_PROFILE="${{ inputs.aws-profile }}"
|
||||
|
||||
# Check if distribution-ids is a file path or literal IDs
|
||||
if [ -f "$DISTRIBUTION_IDS" ]; then
|
||||
IDS=$(cat "$DISTRIBUTION_IDS")
|
||||
else
|
||||
IDS="$DISTRIBUTION_IDS"
|
||||
fi
|
||||
|
||||
for DIST_ID in $IDS; do
|
||||
aws cloudfront create-invalidation \
|
||||
--distribution-id "$DIST_ID" \
|
||||
--paths "$PATHS" \
|
||||
--profile "$AWS_PROFILE"
|
||||
done
|
||||
shell: bash
|
||||
30
.github/actions/docker-build-push/README.md
vendored
Normal file
30
.github/actions/docker-build-push/README.md
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# docker-build-push
|
||||
|
||||
Build Docker image and push to JFrog with semver tags.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `image-name` | Yes | | Image name (e.g., `default-docker/db-devcontainer-base`) |
|
||||
| `version-tag` | Yes | | Full semver tag (e.g., `1.2.3`) |
|
||||
| `jfrog-token` | Yes | | JFrog registry password/token |
|
||||
| `registry` | No | `schmalz.jfrog.io` | Docker registry |
|
||||
| `dockerfile` | No | `Dockerfile` | Path to Dockerfile |
|
||||
| `context` | No | `.` | Docker build context |
|
||||
| `jfrog-user` | No | `jfrog-cicd-user` | JFrog registry user |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/docker-build-push@v1
|
||||
with:
|
||||
image-name: default-docker/my-service
|
||||
version-tag: 1.2.3
|
||||
jfrog-token: ${{ secrets.JFROG_TOKEN }}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Pushes three tags per build: full (`1.2.3`), minor (`1.2`), and major (`1`).
|
||||
- Consumers using the major or minor tag always get the latest patch release.
|
||||
46
.github/actions/docker-build-push/action.yml
vendored
Normal file
46
.github/actions/docker-build-push/action.yml
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
name: docker-build-push
|
||||
description: Build Docker image and push to JFrog with semver tags (major, minor, patch)
|
||||
|
||||
inputs:
|
||||
image-name:
|
||||
description: 'Image name (e.g., default-docker/db-devcontainer-base)'
|
||||
required: true
|
||||
registry:
|
||||
description: 'Docker registry'
|
||||
required: false
|
||||
default: 'schmalz.jfrog.io'
|
||||
dockerfile:
|
||||
description: 'Path to Dockerfile'
|
||||
required: false
|
||||
default: 'Dockerfile'
|
||||
context:
|
||||
description: 'Docker build context'
|
||||
required: false
|
||||
default: '.'
|
||||
version-tag:
|
||||
description: 'Full semver tag (e.g., 1.2.3)'
|
||||
required: true
|
||||
jfrog-token:
|
||||
description: 'JFrog registry password/token'
|
||||
required: true
|
||||
jfrog-user:
|
||||
description: 'JFrog registry user'
|
||||
required: false
|
||||
default: 'jfrog-cicd-user'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Build and push Docker image
|
||||
shell: bash
|
||||
run: |
|
||||
echo "${{ inputs.jfrog-token }}" | docker login "${{ inputs.registry }}" -u "${{ inputs.jfrog-user }}" --password-stdin
|
||||
|
||||
FULL="${{ inputs.registry }}/${{ inputs.image-name }}:${{ inputs.version-tag }}"
|
||||
MINOR="${{ inputs.registry }}/${{ inputs.image-name }}:$(echo "${{ inputs.version-tag }}" | cut -d. -f1,2)"
|
||||
MAJOR="${{ inputs.registry }}/${{ inputs.image-name }}:$(echo "${{ inputs.version-tag }}" | cut -d. -f1)"
|
||||
|
||||
docker build -f "${{ inputs.dockerfile }}" -t "$FULL" -t "$MINOR" -t "$MAJOR" "${{ inputs.context }}"
|
||||
docker push "$FULL"
|
||||
docker push "$MINOR"
|
||||
docker push "$MAJOR"
|
||||
33
.github/actions/helm-deploy/README.md
vendored
Normal file
33
.github/actions/helm-deploy/README.md
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# helm-deploy
|
||||
|
||||
Deploy a service to Kubernetes via Helm over SSH.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `service-name` | Yes | | Helm release name |
|
||||
| `helm-host` | Yes | | SSH target (e.g., `dsp1-stage.schmalzgroup.net`) |
|
||||
| `image-tag` | Yes | | Docker image tag to deploy |
|
||||
| `ssh-key` | Yes | | Private SSH key content |
|
||||
| `overrides-file` | No | `kubernetes/overrides-su.yaml` | Local path to Helm values override file |
|
||||
| `namespace` | No | `dsp` | Kubernetes namespace |
|
||||
| `helm-repo` | No | `nexus-helm-repository` | Helm chart repository name |
|
||||
| `helm-chart` | No | `DSP-Blueprint` | Chart name in the repo |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/helm-deploy@v1
|
||||
with:
|
||||
service-name: my-service
|
||||
helm-host: dsp1-stage.schmalzgroup.net
|
||||
image-tag: ${{ github.sha }}
|
||||
ssh-key: ${{ secrets.SSH_KEY }}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The override file is `scp`-ed to the remote host, then `helm upgrade --install` is run via SSH.
|
||||
- Uses `--atomic` flag, so a failed deploy is automatically rolled back.
|
||||
- `StrictHostKeyChecking` is disabled.
|
||||
55
.github/actions/helm-deploy/action.yml
vendored
Normal file
55
.github/actions/helm-deploy/action.yml
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
name: helm-deploy
|
||||
description: Deploy a service to Kubernetes via Helm over SSH
|
||||
|
||||
inputs:
|
||||
service-name:
|
||||
description: Helm release name
|
||||
required: true
|
||||
helm-host:
|
||||
description: SSH target (e.g., dsp1-stage.schmalzgroup.net)
|
||||
required: true
|
||||
overrides-file:
|
||||
description: Local path to Helm values override file
|
||||
required: false
|
||||
default: kubernetes/overrides-su.yaml
|
||||
image-tag:
|
||||
description: Docker image tag to deploy
|
||||
required: true
|
||||
ssh-key:
|
||||
description: Private SSH key content
|
||||
required: true
|
||||
namespace:
|
||||
description: Kubernetes namespace
|
||||
required: false
|
||||
default: dsp
|
||||
helm-repo:
|
||||
description: Helm chart repository name
|
||||
required: false
|
||||
default: nexus-helm-repository
|
||||
helm-chart:
|
||||
description: Chart name in the repo
|
||||
required: false
|
||||
default: DSP-Blueprint
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- shell: bash
|
||||
run: |
|
||||
SSH_KEY_FILE=$(mktemp)
|
||||
trap "rm -f '$SSH_KEY_FILE'" EXIT
|
||||
|
||||
echo "${{ inputs.ssh-key }}" > "$SSH_KEY_FILE"
|
||||
chmod 600 "$SSH_KEY_FILE"
|
||||
|
||||
SSH_OPTS="-i $SSH_KEY_FILE -o StrictHostKeyChecking=no"
|
||||
REMOTE="root@${{ inputs.helm-host }}"
|
||||
SERVICE="${{ inputs.service-name }}"
|
||||
|
||||
scp $SSH_OPTS "${{ inputs.overrides-file }}" "$REMOTE:/tmp/${SERVICE}-overrides.yaml"
|
||||
|
||||
ssh $SSH_OPTS "$REMOTE" \
|
||||
"helm repo update && \
|
||||
helm upgrade --install --create-namespace -n ${{ inputs.namespace }} $SERVICE \
|
||||
${{ inputs.helm-repo }}/${{ inputs.helm-chart }} -f /tmp/${SERVICE}-overrides.yaml \
|
||||
--set image.tag=${{ inputs.image-tag }} --atomic --debug"
|
||||
32
.github/actions/maven-build/README.md
vendored
Normal file
32
.github/actions/maven-build/README.md
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# maven-build
|
||||
|
||||
Run a Maven build -- verify-only for PRs or package+jib push for deploys.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `maven-settings` | Yes | | Secret containing `settings.xml` content |
|
||||
| `java-version` | No | `8` | Java version |
|
||||
| `maven-image` | No | `maven:3.8.5-openjdk-8` | Maven Docker image |
|
||||
| `phase` | No | `verify` | Build phase: `verify` or `package-and-push` |
|
||||
| `verify-goals` | No | `spotless:check checkstyle:check compile` | Goals for the verify phase |
|
||||
| `maven-profile` | No | `test` | Maven profile used during `package-and-push` |
|
||||
| `service-dir` | No | `.` | Working directory containing the POM |
|
||||
| `skip-tests` | No | `false` | Pass `-DskipTests` |
|
||||
| `image-tag` | No | `${{ github.sha }}-${{ github.run_id }}` | Docker image tag for jib |
|
||||
| `extra-args` | No | | Additional Maven CLI arguments |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/maven-build@v1
|
||||
with:
|
||||
maven-settings: ${{ secrets.MAVEN_SETTINGS }}
|
||||
phase: package-and-push
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Maven repository cache is restored/saved automatically using `pom.xml` hash.
|
||||
- The `settings.xml` is written to a temp file and cleaned up after the build.
|
||||
74
.github/actions/maven-build/action.yml
vendored
Normal file
74
.github/actions/maven-build/action.yml
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
name: maven-build
|
||||
description: Run Maven build — verify-only (PRs) or package+jib push (deploy)
|
||||
|
||||
inputs:
|
||||
phase:
|
||||
required: false
|
||||
default: 'verify'
|
||||
verify-goals:
|
||||
required: false
|
||||
default: 'spotless:check checkstyle:check compile'
|
||||
maven-profile:
|
||||
required: false
|
||||
default: 'test'
|
||||
service-dir:
|
||||
required: false
|
||||
default: '.'
|
||||
skip-tests:
|
||||
required: false
|
||||
default: 'false'
|
||||
image-tag:
|
||||
required: false
|
||||
default: '${{ github.sha }}-${{ github.run_id }}'
|
||||
maven-settings:
|
||||
required: true
|
||||
description: Secret containing settings.xml content
|
||||
extra-args:
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Restore Maven cache
|
||||
uses: https://data.forgejo.org/actions/cache/restore@v4
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: maven-${{ hashFiles('**/pom.xml') }}
|
||||
|
||||
- name: Maven build
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.service-dir }}
|
||||
run: |
|
||||
SETTINGS_FILE=$(mktemp)
|
||||
echo "${{ inputs.maven-settings }}" > "$SETTINGS_FILE"
|
||||
trap 'rm -f "$SETTINGS_FILE"' EXIT
|
||||
|
||||
SKIP_TESTS_FLAG=""
|
||||
if [ "${{ inputs.skip-tests }}" = "true" ]; then
|
||||
SKIP_TESTS_FLAG="-DskipTests"
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.phase }}" = "verify" ]; then
|
||||
mvn ${{ inputs.verify-goals }} \
|
||||
-s "$SETTINGS_FILE" \
|
||||
$SKIP_TESTS_FLAG \
|
||||
${{ inputs.extra-args }}
|
||||
elif [ "${{ inputs.phase }}" = "package-and-push" ]; then
|
||||
mvn clean package jib:build \
|
||||
-DsendCredentialsOverHttp=true \
|
||||
-Djib.to.tags=${{ inputs.image-tag }} \
|
||||
-P ${{ inputs.maven-profile }} \
|
||||
-s "$SETTINGS_FILE" \
|
||||
$SKIP_TESTS_FLAG \
|
||||
${{ inputs.extra-args }}
|
||||
else
|
||||
echo "Unknown phase: ${{ inputs.phase }}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Save Maven cache
|
||||
uses: https://data.forgejo.org/actions/cache/save@v4
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: maven-${{ hashFiles('**/pom.xml') }}
|
||||
38
.github/actions/playwright-e2e/README.md
vendored
Normal file
38
.github/actions/playwright-e2e/README.md
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# playwright-e2e
|
||||
|
||||
Run Playwright E2E tests with optional sharding, upload results to S3.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `jfrog-token` | Yes | | JFrog npm auth token |
|
||||
| `s3-reports-bucket` | Yes | | S3 bucket for report upload |
|
||||
| `s3-reports-prefix` | Yes | | S3 path prefix |
|
||||
| `aws-role-arn` | Yes | | IAM role ARN for OIDC authentication |
|
||||
| `working-directory` | No | `e2e` | Directory containing Playwright config |
|
||||
| `playwright-version` | No | `v1.58.2` | Playwright version tag for browser cache key |
|
||||
| `pnpm-version` | No | `10.11` | pnpm version |
|
||||
| `shard-index` | No | `1` | Current shard (1-based) |
|
||||
| `shard-total` | No | `1` | Total shards. 1 = no sharding |
|
||||
| `aws-profile` | No | `stage` | AWS CLI profile name |
|
||||
| `extra-deps` | No | `""` | Space-separated apt packages to install |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/playwright-e2e@v1
|
||||
with:
|
||||
jfrog-token: ${{ secrets.JFROG_TOKEN }}
|
||||
s3-reports-bucket: my-reports-bucket
|
||||
s3-reports-prefix: pr-${{ github.event.number }}
|
||||
aws-role-arn: ${{ secrets.AWS_ROLE_ARN }}
|
||||
shard-index: "1"
|
||||
shard-total: "4"
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Playwright browsers are cached between runs using the `playwright-version` input as cache key.
|
||||
- Reports are uploaded to `s3://<bucket>/<prefix>/shard-<index>/`.
|
||||
- Uses JFrog Artifactory as the npm registry for dependency installation.
|
||||
109
.github/actions/playwright-e2e/action.yml
vendored
Normal file
109
.github/actions/playwright-e2e/action.yml
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
name: playwright-e2e
|
||||
description: Run Playwright E2E tests with optional sharding, upload results to S3.
|
||||
|
||||
inputs:
|
||||
working-directory:
|
||||
description: Directory containing Playwright config
|
||||
required: false
|
||||
default: e2e
|
||||
playwright-version:
|
||||
description: Playwright version tag (browser cache key only — actual version comes from pnpm-lock.yaml)
|
||||
required: false
|
||||
default: v1.58.2
|
||||
jfrog-token:
|
||||
description: JFrog npm auth token
|
||||
required: true
|
||||
pnpm-version:
|
||||
description: pnpm version
|
||||
required: false
|
||||
default: "10.11"
|
||||
node-version:
|
||||
description: Node.js version
|
||||
required: false
|
||||
default: "22"
|
||||
shard-index:
|
||||
description: Current shard (1-based)
|
||||
required: false
|
||||
default: "1"
|
||||
shard-total:
|
||||
description: Total shards. 1 = no sharding.
|
||||
required: false
|
||||
default: "1"
|
||||
s3-reports-bucket:
|
||||
description: S3 bucket for report upload
|
||||
required: true
|
||||
s3-reports-prefix:
|
||||
description: S3 path prefix
|
||||
required: true
|
||||
aws-role-arn:
|
||||
description: IAM role ARN for OIDC authentication
|
||||
required: true
|
||||
aws-profile:
|
||||
description: AWS CLI profile name
|
||||
required: false
|
||||
default: stage
|
||||
extra-deps:
|
||||
description: Space-separated apt packages to install
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Configure AWS
|
||||
uses: schmalz/shared-actions/.github/actions/aws-configure@v1
|
||||
with:
|
||||
role-arn: ${{ inputs.aws-role-arn }}
|
||||
aws-profile: ${{ inputs.aws-profile }}
|
||||
|
||||
- name: Restore Playwright browser cache
|
||||
uses: https://data.forgejo.org/actions/cache/restore@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-${{ inputs.playwright-version }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: https://code.forgejo.org/actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
|
||||
- name: Run Playwright tests and upload results
|
||||
shell: bash
|
||||
env:
|
||||
EXTRA_DEPS: ${{ inputs.extra-deps }}
|
||||
PNPM_VERSION: ${{ inputs.pnpm-version }}
|
||||
JFROG_TOKEN: ${{ inputs.jfrog-token }}
|
||||
WORKING_DIR: ${{ inputs.working-directory }}
|
||||
SHARD_INDEX: ${{ inputs.shard-index }}
|
||||
SHARD_TOTAL: ${{ inputs.shard-total }}
|
||||
BUCKET: ${{ inputs.s3-reports-bucket }}
|
||||
PREFIX: ${{ inputs.s3-reports-prefix }}
|
||||
AWS_PROFILE: ${{ inputs.aws-profile }}
|
||||
run: |
|
||||
if [ -n "${EXTRA_DEPS}" ]; then
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y ${EXTRA_DEPS}
|
||||
fi
|
||||
|
||||
npm i -g "pnpm@${PNPM_VERSION}"
|
||||
pnpm set registry https://schmalz.jfrog.io/artifactory/api/npm/default-npm/
|
||||
pnpm set "//schmalz.jfrog.io/artifactory/api/npm/default-npm/:_authToken=${JFROG_TOKEN}"
|
||||
|
||||
pnpm --prefix="${WORKING_DIR}" install --frozen-lockfile
|
||||
pnpm --prefix="${WORKING_DIR}" exec playwright install --with-deps
|
||||
|
||||
SHARD_ARG=""
|
||||
if [ "${SHARD_TOTAL}" != "1" ]; then
|
||||
SHARD_ARG="--shard=${SHARD_INDEX}/${SHARD_TOTAL}"
|
||||
fi
|
||||
pnpm --prefix="${WORKING_DIR}" exec playwright test ${SHARD_ARG}
|
||||
|
||||
aws s3 sync "${WORKING_DIR}/playwright-report/" \
|
||||
"s3://${BUCKET}/${PREFIX}/shard-${SHARD_INDEX}/" \
|
||||
--profile "${AWS_PROFILE}"
|
||||
|
||||
- name: Save Playwright browser cache
|
||||
uses: https://data.forgejo.org/actions/cache/save@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-${{ inputs.playwright-version }}
|
||||
28
.github/actions/pnpm-build/README.md
vendored
Normal file
28
.github/actions/pnpm-build/README.md
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# pnpm-build
|
||||
|
||||
Set up pnpm, authenticate with JFrog npm registry, install dependencies, and run build scripts.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `jfrog-token` | Yes | | JFrog npm auth token |
|
||||
| `working-directory` | No | `.` | Directory containing `package.json` |
|
||||
| `pnpm-version` | No | `10.14` | pnpm version |
|
||||
| `node-version` | No | `22` | Node.js version |
|
||||
| `run-scripts` | No | `ci,typecheck,build` | Comma-separated list of `pnpm run` scripts |
|
||||
| `frozen-lockfile` | No | `true` | Pass `--frozen-lockfile` to `pnpm install` |
|
||||
| `check-dedupe` | No | `true` | Run `pnpm dedupe --check` |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/pnpm-build@v1
|
||||
with:
|
||||
jfrog-token: ${{ secrets.JFROG_TOKEN }}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- pnpm store cache is restored/saved automatically using `pnpm-lock.yaml` hash.
|
||||
- Registry is set to `schmalz.jfrog.io`.
|
||||
80
.github/actions/pnpm-build/action.yml
vendored
Normal file
80
.github/actions/pnpm-build/action.yml
vendored
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
name: pnpm-build
|
||||
description: Set up pnpm, authenticate JFrog npm registry, install deps, run scripts.
|
||||
|
||||
inputs:
|
||||
working-directory:
|
||||
description: Directory containing package.json
|
||||
required: false
|
||||
default: "."
|
||||
pnpm-version:
|
||||
description: pnpm version
|
||||
required: false
|
||||
default: "10.14"
|
||||
jfrog-token:
|
||||
description: JFrog npm auth token
|
||||
required: true
|
||||
run-scripts:
|
||||
description: Comma-separated list of pnpm run scripts
|
||||
required: false
|
||||
default: "ci,typecheck,build"
|
||||
frozen-lockfile:
|
||||
description: Pass --frozen-lockfile to pnpm install
|
||||
required: false
|
||||
default: "true"
|
||||
check-dedupe:
|
||||
description: Run pnpm dedupe --check
|
||||
required: false
|
||||
default: "true"
|
||||
node-version:
|
||||
description: Node.js version
|
||||
required: false
|
||||
default: "22"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Restore pnpm cache
|
||||
uses: https://data.forgejo.org/actions/cache/restore@v4
|
||||
with:
|
||||
path: ~/.local/share/pnpm/store/v3
|
||||
key: pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: https://code.forgejo.org/actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
|
||||
- name: Setup and build
|
||||
shell: bash
|
||||
env:
|
||||
PNPM_VERSION: ${{ inputs.pnpm-version }}
|
||||
JFROG_TOKEN: ${{ inputs.jfrog-token }}
|
||||
WORKING_DIR: ${{ inputs.working-directory }}
|
||||
RUN_SCRIPTS: ${{ inputs.run-scripts }}
|
||||
FROZEN_LOCKFILE: ${{ inputs.frozen-lockfile }}
|
||||
CHECK_DEDUPE: ${{ inputs.check-dedupe }}
|
||||
run: |
|
||||
npm i -g "pnpm@${PNPM_VERSION}"
|
||||
pnpm set registry https://schmalz.jfrog.io/artifactory/api/npm/default-npm/
|
||||
pnpm set "//schmalz.jfrog.io/artifactory/api/npm/default-npm/:_authToken=${JFROG_TOKEN}"
|
||||
|
||||
if [ "${CHECK_DEDUPE}" = "true" ]; then
|
||||
pnpm --prefix="${WORKING_DIR}" dedupe --check
|
||||
fi
|
||||
|
||||
INSTALL_ARGS=""
|
||||
if [ "${FROZEN_LOCKFILE}" = "true" ]; then
|
||||
INSTALL_ARGS="--frozen-lockfile"
|
||||
fi
|
||||
pnpm --prefix="${WORKING_DIR}" install ${INSTALL_ARGS}
|
||||
|
||||
IFS=',' read -ra SCRIPTS <<< "${RUN_SCRIPTS}"
|
||||
for script in "${SCRIPTS[@]}"; do
|
||||
pnpm --prefix="${WORKING_DIR}" run "${script}"
|
||||
done
|
||||
|
||||
- name: Save pnpm cache
|
||||
uses: https://data.forgejo.org/actions/cache/save@v4
|
||||
with:
|
||||
path: ~/.local/share/pnpm/store/v3
|
||||
key: pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
26
.github/actions/publish-npm-package/README.md
vendored
Normal file
26
.github/actions/publish-npm-package/README.md
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# publish-npm-package
|
||||
|
||||
Build and publish npm package to JFrog Artifactory.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `jfrog-token` | Yes | | JFrog npm auth token |
|
||||
| `working-directory` | No | `.` | Directory containing package.json |
|
||||
| `pnpm-version` | No | `10.14` | pnpm version |
|
||||
| `registry-url` | No | `https://schmalz.jfrog.io/artifactory/api/npm/default-npm/` | JFrog npm registry URL |
|
||||
| `build-script` | No | `build` | pnpm build script name |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/publish-npm-package@v1
|
||||
with:
|
||||
jfrog-token: ${{ secrets.JFROG_TOKEN }}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Runs `pnpm install --frozen-lockfile`, then the build script, then `pnpm publish --no-git-checks`.
|
||||
- The version published is whatever is in `package.json` -- bump it before calling this action.
|
||||
51
.github/actions/publish-npm-package/action.yml
vendored
Normal file
51
.github/actions/publish-npm-package/action.yml
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
name: publish-npm-package
|
||||
description: Build and publish npm package to JFrog Artifactory.
|
||||
|
||||
inputs:
|
||||
working-directory:
|
||||
description: Directory containing package.json
|
||||
required: false
|
||||
default: "."
|
||||
pnpm-version:
|
||||
description: pnpm version
|
||||
required: false
|
||||
default: "10.14"
|
||||
node-version:
|
||||
description: Node.js version
|
||||
required: false
|
||||
default: "22"
|
||||
jfrog-token:
|
||||
description: JFrog npm auth token
|
||||
required: true
|
||||
registry-url:
|
||||
description: JFrog npm registry URL
|
||||
required: false
|
||||
default: "https://schmalz.jfrog.io/artifactory/api/npm/default-npm/"
|
||||
build-script:
|
||||
description: pnpm build script name
|
||||
required: false
|
||||
default: "build"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup Node.js
|
||||
uses: https://code.forgejo.org/actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
|
||||
- name: Build and publish
|
||||
shell: bash
|
||||
env:
|
||||
PNPM_VERSION: ${{ inputs.pnpm-version }}
|
||||
JFROG_TOKEN: ${{ inputs.jfrog-token }}
|
||||
REGISTRY_URL: ${{ inputs.registry-url }}
|
||||
WORKING_DIR: ${{ inputs.working-directory }}
|
||||
BUILD_SCRIPT: ${{ inputs.build-script }}
|
||||
run: |
|
||||
npm i -g "pnpm@${PNPM_VERSION}"
|
||||
pnpm set registry "${REGISTRY_URL}"
|
||||
pnpm set "//schmalz.jfrog.io/artifactory/api/npm/default-npm/:_authToken=${JFROG_TOKEN}"
|
||||
pnpm --prefix="${WORKING_DIR}" install --frozen-lockfile
|
||||
pnpm --prefix="${WORKING_DIR}" run "${BUILD_SCRIPT}"
|
||||
pnpm --prefix="${WORKING_DIR}" publish --no-git-checks
|
||||
26
.github/actions/publish-rust-crate/README.md
vendored
Normal file
26
.github/actions/publish-rust-crate/README.md
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# publish-rust-crate
|
||||
|
||||
Build, test, and publish Rust crate to JFrog Cargo registry.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `jfrog-token` | Yes | | JFrog access token for Cargo registry auth |
|
||||
| `working-directory` | No | `.` | Directory containing Cargo.toml |
|
||||
| `rust-version` | No | `1.87` | Rust toolchain version |
|
||||
| `cargo-registry-name` | No | `jfrog` | Cargo registry name |
|
||||
| `run-tests` | No | `true` | Run `cargo test` before publishing |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/publish-rust-crate@v1
|
||||
with:
|
||||
jfrog-token: ${{ secrets.JFROG_TOKEN }}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The registry token is set via `CARGO_REGISTRIES_<NAME>_TOKEN` environment variable (registry name is uppercased).
|
||||
- The crate version published is whatever is in `Cargo.toml` -- bump it before calling this action.
|
||||
42
.github/actions/publish-rust-crate/action.yml
vendored
Normal file
42
.github/actions/publish-rust-crate/action.yml
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
name: publish-rust-crate
|
||||
description: Build, test, and publish Rust crate to JFrog Cargo registry.
|
||||
|
||||
inputs:
|
||||
working-directory:
|
||||
description: Directory containing Cargo.toml
|
||||
required: false
|
||||
default: "."
|
||||
rust-version:
|
||||
description: Rust toolchain version
|
||||
required: false
|
||||
default: "1.87"
|
||||
cargo-registry-name:
|
||||
description: Cargo registry name
|
||||
required: false
|
||||
default: "jfrog"
|
||||
jfrog-token:
|
||||
description: JFrog access token for Cargo registry auth
|
||||
required: true
|
||||
run-tests:
|
||||
description: Run cargo test before publishing
|
||||
required: false
|
||||
default: "true"
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Test and publish
|
||||
shell: bash
|
||||
env:
|
||||
RUST_VERSION: ${{ inputs.rust-version }}
|
||||
REGISTRY_NAME: ${{ inputs.cargo-registry-name }}
|
||||
JFROG_TOKEN: ${{ inputs.jfrog-token }}
|
||||
WORKING_DIR: ${{ inputs.working-directory }}
|
||||
RUN_TESTS: ${{ inputs.run-tests }}
|
||||
run: |
|
||||
rustup default "${RUST_VERSION}"
|
||||
UPPER_NAME="$(echo "${REGISTRY_NAME}" | tr '[:lower:]' '[:upper:]')"
|
||||
export "CARGO_REGISTRIES_${UPPER_NAME}_TOKEN=Bearer ${JFROG_TOKEN}"
|
||||
cd "${WORKING_DIR}"
|
||||
if [ "${RUN_TESTS}" = "true" ]; then cargo test; fi
|
||||
cargo publish --registry "${REGISTRY_NAME}"
|
||||
42
.github/actions/rust-build/README.md
vendored
Normal file
42
.github/actions/rust-build/README.md
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# rust-build
|
||||
|
||||
Run Rust CI -- fmt, clippy, tests, optional cross-compilation.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `toolchain` | No | `stable` | Rust toolchain |
|
||||
| `features` | No | `""` | Cargo features to enable |
|
||||
| `cross-target` | No | `""` | Cross-compilation target (installs `cross` when set) |
|
||||
| `run-fmt` | No | `true` | Run `cargo fmt --check` |
|
||||
| `run-clippy` | No | `true` | Run clippy with `-D warnings` |
|
||||
| `run-tests` | No | `true` | Run `cargo test` |
|
||||
| `run-deny` | No | `false` | Run `cargo deny check` |
|
||||
| `run-semver-checks` | No | `false` | Run `cargo semver-checks` |
|
||||
| `sccache-enabled` | No | `true` | Enable sccache (requires `sccache_ci_setup.sh` in working directory) |
|
||||
| `working-directory` | No | `.` | Working directory |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/rust-build@v1
|
||||
with:
|
||||
features: serde,tokio
|
||||
run-deny: "true"
|
||||
```
|
||||
|
||||
### Cross-compilation
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/rust-build@v1
|
||||
with:
|
||||
cross-target: aarch64-unknown-linux-gnu
|
||||
run-fmt: "false"
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Cargo registry and `target/` directory are cached based on `Cargo.lock` hash.
|
||||
- When `cross-target` is set, `cross` is installed and used instead of `cargo` for clippy, test, and build steps. `cargo fmt` always uses `cargo` directly.
|
||||
- sccache integration requires a `sccache_ci_setup.sh` script in the working directory.
|
||||
101
.github/actions/rust-build/action.yml
vendored
Normal file
101
.github/actions/rust-build/action.yml
vendored
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
name: rust-build
|
||||
description: Run Rust CI — fmt, clippy, tests, optional cross-compilation.
|
||||
|
||||
inputs:
|
||||
toolchain:
|
||||
required: false
|
||||
default: "stable"
|
||||
features:
|
||||
required: false
|
||||
default: ""
|
||||
cross-target:
|
||||
required: false
|
||||
default: ""
|
||||
run-fmt:
|
||||
required: false
|
||||
default: "true"
|
||||
run-clippy:
|
||||
required: false
|
||||
default: "true"
|
||||
run-tests:
|
||||
required: false
|
||||
default: "true"
|
||||
run-deny:
|
||||
required: false
|
||||
default: "false"
|
||||
run-semver-checks:
|
||||
required: false
|
||||
default: "false"
|
||||
sccache-enabled:
|
||||
required: false
|
||||
default: "true"
|
||||
working-directory:
|
||||
required: false
|
||||
default: "."
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Restore cargo cache
|
||||
uses: https://data.forgejo.org/actions/cache/restore@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
target/
|
||||
key: cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
|
||||
- name: Rust CI
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.working-directory }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
rustup default ${{ inputs.toolchain }}
|
||||
|
||||
if [[ "${{ inputs.sccache-enabled }}" == "true" && -f sccache_ci_setup.sh ]]; then
|
||||
source sccache_ci_setup.sh
|
||||
fi
|
||||
|
||||
CMD=cargo
|
||||
if [[ -n "${{ inputs.cross-target }}" ]]; then
|
||||
cargo install cross
|
||||
CMD=cross
|
||||
fi
|
||||
|
||||
FEATURES_ARG=""
|
||||
if [[ -n "${{ inputs.features }}" ]]; then
|
||||
FEATURES_ARG="--features ${{ inputs.features }}"
|
||||
fi
|
||||
|
||||
TARGET_ARG=""
|
||||
if [[ -n "${{ inputs.cross-target }}" ]]; then
|
||||
TARGET_ARG="--target ${{ inputs.cross-target }}"
|
||||
fi
|
||||
|
||||
if [[ "${{ inputs.run-fmt }}" == "true" ]]; then
|
||||
cargo fmt --check
|
||||
fi
|
||||
|
||||
if [[ "${{ inputs.run-clippy }}" == "true" ]]; then
|
||||
$CMD clippy $FEATURES_ARG $TARGET_ARG -- -D warnings
|
||||
fi
|
||||
|
||||
if [[ "${{ inputs.run-tests }}" == "true" ]]; then
|
||||
$CMD test $FEATURES_ARG $TARGET_ARG
|
||||
fi
|
||||
|
||||
if [[ "${{ inputs.run-deny }}" == "true" ]]; then
|
||||
cargo deny check
|
||||
fi
|
||||
|
||||
if [[ "${{ inputs.run-semver-checks }}" == "true" ]]; then
|
||||
cargo semver-checks
|
||||
fi
|
||||
|
||||
- name: Save cargo cache
|
||||
uses: https://data.forgejo.org/actions/cache/save@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
target/
|
||||
key: cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
23
.github/actions/secrets-inject/README.md
vendored
Normal file
23
.github/actions/secrets-inject/README.md
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# secrets-inject
|
||||
|
||||
Append secret properties content to a Java `.properties` file.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `secret-content` | Yes | | Properties content to append |
|
||||
| `target-file` | Yes | | Path to the `.properties` file |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/secrets-inject@v1
|
||||
with:
|
||||
secret-content: ${{ secrets.APP_SECRETS }}
|
||||
target-file: src/main/resources/application.properties
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- A blank line is inserted before the appended content to avoid merging with the last existing line.
|
||||
18
.github/actions/secrets-inject/action.yml
vendored
Normal file
18
.github/actions/secrets-inject/action.yml
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
name: secrets-inject
|
||||
description: Append a secrets file to a Java .properties file
|
||||
|
||||
inputs:
|
||||
secret-content:
|
||||
description: Secret value (properties content to append)
|
||||
required: true
|
||||
target-file:
|
||||
description: Path to the .properties file
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- run: |
|
||||
echo "" >> ${{ inputs.target-file }}
|
||||
echo "${{ inputs.secret-content }}" >> ${{ inputs.target-file }}
|
||||
shell: bash
|
||||
38
.github/actions/terraform-apply/README.md
vendored
Normal file
38
.github/actions/terraform-apply/README.md
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# terraform-apply
|
||||
|
||||
Full Terraform init, workspace select, plan/apply, and output capture.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `var-file` | Yes | | Path to `.tfvars` file |
|
||||
| `workspace` | Yes | | Terraform workspace (`stage` or `prod`) |
|
||||
| `aws-role-arn` | Yes | | IAM role ARN for OIDC authentication |
|
||||
| `jfrog-token` | Yes | | JFrog access token (sets `TF_TOKEN_schmalz_jfrog_io`) |
|
||||
| `terraform-dir` | No | `terraform` | Directory containing Terraform configuration |
|
||||
| `terraform-version` | No | `1.11` | Terraform version to install |
|
||||
| `aws-profile` | No | `default` | AWS CLI profile name |
|
||||
| `output-names` | No | `""` | Comma-separated Terraform output names to capture as raw values |
|
||||
| `output-json-names` | No | `""` | Comma-separated output names to capture as JSON |
|
||||
| `plan-only` | No | `false` | Run `plan -out` instead of `apply` |
|
||||
| `plan-file` | No | `""` | Pre-existing plan file to apply |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/terraform-apply@v1
|
||||
with:
|
||||
var-file: envs/stage.tfvars
|
||||
workspace: stage
|
||||
aws-role-arn: arn:aws:iam::123456789012:role/my-role
|
||||
jfrog-token: ${{ secrets.JFROG_TOKEN }}
|
||||
output-names: api_url,db_host
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Requires `enable-openid-connect: true` on the job.
|
||||
- Captured outputs are written to `$FORGEJO_OUTPUT` and to files under `<terraform-dir>/.outputs/`.
|
||||
- Provider cache is restored/saved automatically.
|
||||
- Use `plan-only: true` for a plan-then-apply workflow across jobs.
|
||||
118
.github/actions/terraform-apply/action.yml
vendored
Normal file
118
.github/actions/terraform-apply/action.yml
vendored
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
name: terraform-apply
|
||||
description: Full Terraform init + workspace + apply + output capture
|
||||
|
||||
inputs:
|
||||
terraform-dir:
|
||||
description: Directory containing Terraform configuration
|
||||
required: false
|
||||
default: terraform
|
||||
terraform-version:
|
||||
description: Terraform version to install
|
||||
required: false
|
||||
default: "1.11"
|
||||
var-file:
|
||||
description: Path to .tfvars file
|
||||
required: true
|
||||
workspace:
|
||||
description: Terraform workspace (stage or prod)
|
||||
required: true
|
||||
aws-role-arn:
|
||||
description: IAM role ARN for OIDC authentication
|
||||
required: true
|
||||
aws-profile:
|
||||
description: AWS profile name
|
||||
required: false
|
||||
default: default
|
||||
jfrog-token:
|
||||
description: JFrog access token (sets TF_TOKEN_schmalz_jfrog_io)
|
||||
required: true
|
||||
output-names:
|
||||
description: Comma-separated list of terraform output names to capture as raw
|
||||
required: false
|
||||
default: ""
|
||||
plan-only:
|
||||
description: Run plan -out instead of apply
|
||||
required: false
|
||||
default: "false"
|
||||
plan-file:
|
||||
description: Pre-existing plan file to apply
|
||||
required: false
|
||||
default: ""
|
||||
output-json-names:
|
||||
description: Comma-separated output names to capture as JSON
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Configure AWS credentials
|
||||
uses: schmalz/shared-actions/.github/actions/aws-configure@v1
|
||||
with:
|
||||
role-arn: ${{ inputs.aws-role-arn }}
|
||||
aws-profile: ${{ inputs.aws-profile }}
|
||||
|
||||
- name: Restore Terraform provider cache
|
||||
uses: https://data.forgejo.org/actions/cache/restore@v4
|
||||
with:
|
||||
path: ${{ inputs.terraform-dir }}/.terraform/providers
|
||||
key: terraform-providers-${{ hashFiles(format('{0}/.terraform.lock.hcl', inputs.terraform-dir)) }}
|
||||
|
||||
- name: Install Terraform
|
||||
shell: bash
|
||||
run: |
|
||||
TF_VERSION="${{ inputs.terraform-version }}"
|
||||
curl -fsSL "https://releases.hashicorp.com/terraform/${TF_VERSION}/terraform_${TF_VERSION}_linux_amd64.zip" -o /tmp/terraform.zip
|
||||
sudo unzip -o /tmp/terraform.zip -d /usr/local/bin
|
||||
rm /tmp/terraform.zip
|
||||
terraform version
|
||||
|
||||
- name: Terraform init, plan/apply, and capture outputs
|
||||
shell: bash
|
||||
env:
|
||||
TF_TOKEN_schmalz_jfrog_io: ${{ inputs.jfrog-token }}
|
||||
TF_WORKSPACE: ${{ inputs.workspace }}
|
||||
AWS_PROFILE: ${{ inputs.aws-profile }}
|
||||
TF_DIR: ${{ inputs.terraform-dir }}
|
||||
VAR_FILE: ${{ inputs.var-file }}
|
||||
PLAN_ONLY: ${{ inputs.plan-only }}
|
||||
PLAN_FILE: ${{ inputs.plan-file }}
|
||||
OUTPUT_NAMES: ${{ inputs.output-names }}
|
||||
OUTPUT_JSON_NAMES: ${{ inputs.output-json-names }}
|
||||
run: |
|
||||
terraform -chdir="$TF_DIR" init -no-color
|
||||
|
||||
if [ "$PLAN_ONLY" = "true" ]; then
|
||||
terraform -chdir="$TF_DIR" plan -var-file="$VAR_FILE" -out=terraform.plan -no-color
|
||||
elif [ -n "$PLAN_FILE" ]; then
|
||||
terraform -chdir="$TF_DIR" apply -auto-approve -no-color "$PLAN_FILE"
|
||||
else
|
||||
terraform -chdir="$TF_DIR" apply -var-file="$VAR_FILE" -auto-approve -no-color
|
||||
fi
|
||||
|
||||
mkdir -p "$TF_DIR/.outputs"
|
||||
|
||||
if [ -n "$OUTPUT_NAMES" ]; then
|
||||
IFS=',' read -ra NAMES <<< "$OUTPUT_NAMES"
|
||||
for name in "${NAMES[@]}"; do
|
||||
name=$(echo "$name" | xargs)
|
||||
val=$(terraform -chdir="$TF_DIR" output --raw "$name")
|
||||
echo "$val" > "$TF_DIR/.outputs/$name"
|
||||
echo "$name=$val" >> "$FORGEJO_OUTPUT"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -n "$OUTPUT_JSON_NAMES" ]; then
|
||||
IFS=',' read -ra JNAMES <<< "$OUTPUT_JSON_NAMES"
|
||||
for name in "${JNAMES[@]}"; do
|
||||
name=$(echo "$name" | xargs)
|
||||
terraform -chdir="$TF_DIR" output --json "$name" > "$TF_DIR/.outputs/$name.json"
|
||||
echo "$name=$(terraform -chdir="$TF_DIR" output --json "$name")" >> "$FORGEJO_OUTPUT"
|
||||
done
|
||||
fi
|
||||
|
||||
- name: Save Terraform provider cache
|
||||
uses: https://data.forgejo.org/actions/cache/save@v4
|
||||
with:
|
||||
path: ${{ inputs.terraform-dir }}/.terraform/providers
|
||||
key: terraform-providers-${{ hashFiles(format('{0}/.terraform.lock.hcl', inputs.terraform-dir)) }}
|
||||
29
.github/actions/terraform-module-publish/README.md
vendored
Normal file
29
.github/actions/terraform-module-publish/README.md
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
# terraform-module-publish
|
||||
|
||||
Zip a Terraform module and publish to JFrog Artifactory.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `module-dir` | Yes | | Path to the module directory to zip |
|
||||
| `module-name` | Yes | | Module name (used in zip filename and upload path) |
|
||||
| `version` | Yes | | Version string (from git tag) |
|
||||
| `jfrog-token` | Yes | | JFrog access token |
|
||||
| `jfrog-url` | No | `https://schmalz.jfrog.io/artifactory/terraform/schmalz` | JFrog Artifactory base URL |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/terraform-module-publish@v1
|
||||
with:
|
||||
module-dir: modules/vpc
|
||||
module-name: vpc
|
||||
version: ${{ github.ref_name }}
|
||||
jfrog-token: ${{ secrets.JFROG_TOKEN }}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- The module directory contents are zipped and uploaded to `<jfrog-url>/<module-name>/<version>.zip`.
|
||||
- Uses `curl` with bearer token authentication.
|
||||
32
.github/actions/terraform-module-publish/action.yml
vendored
Normal file
32
.github/actions/terraform-module-publish/action.yml
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
name: terraform-module-publish
|
||||
description: Zip a Terraform module and publish to JFrog Artifactory
|
||||
|
||||
inputs:
|
||||
module-dir:
|
||||
description: Path to the module directory to zip
|
||||
required: true
|
||||
module-name:
|
||||
description: Module name (used in zip filename and upload path)
|
||||
required: true
|
||||
version:
|
||||
description: Version string (from git tag)
|
||||
required: true
|
||||
jfrog-url:
|
||||
description: JFrog Artifactory base URL
|
||||
required: false
|
||||
default: https://schmalz.jfrog.io/artifactory/terraform/schmalz
|
||||
jfrog-token:
|
||||
description: JFrog access token
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Zip and publish module
|
||||
shell: bash
|
||||
run: |
|
||||
cd "${{ inputs.module-dir }}"
|
||||
zip -r "/tmp/${{ inputs.module-name }}-${{ inputs.version }}.zip" .
|
||||
curl -sf -H "Authorization: Bearer ${{ inputs.jfrog-token }}" \
|
||||
-T "/tmp/${{ inputs.module-name }}-${{ inputs.version }}.zip" \
|
||||
"${{ inputs.jfrog-url }}/${{ inputs.module-name }}/${{ inputs.version }}.zip"
|
||||
28
.github/actions/terraform-validate/README.md
vendored
Normal file
28
.github/actions/terraform-validate/README.md
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# terraform-validate
|
||||
|
||||
Validate Terraform code without a backend (for PR checks).
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `jfrog-token` | Yes | | Sets `TF_TOKEN_schmalz_jfrog_io` for provider auth |
|
||||
| `terraform-dir` | No | `terraform` | Directory containing `.tf` files |
|
||||
| `terraform-version` | No | `1.11` | Terraform version to use |
|
||||
| `aws-role-arn` | No | `""` | If provided, runs `aws-configure` before validate |
|
||||
| `aws-profile` | No | `stage` | AWS profile when `aws-role-arn` is given |
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- uses: schmalz/shared-actions/.github/actions/terraform-validate@v1
|
||||
with:
|
||||
jfrog-token: ${{ secrets.JFROG_TOKEN }}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Runs `terraform init -backend=false`, `terraform fmt -check -recursive`, and `terraform validate`.
|
||||
- Sets `TF_WORKSPACE=stage` during init.
|
||||
- Provider cache is restored/saved automatically.
|
||||
- Optionally configures AWS credentials if `aws-role-arn` is provided (requires `enable-openid-connect: true`).
|
||||
59
.github/actions/terraform-validate/action.yml
vendored
Normal file
59
.github/actions/terraform-validate/action.yml
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
name: terraform-validate
|
||||
description: Validate Terraform code without backend (for PR checks)
|
||||
|
||||
inputs:
|
||||
terraform-dir:
|
||||
description: Directory containing .tf files
|
||||
required: false
|
||||
default: terraform
|
||||
terraform-version:
|
||||
description: Terraform version to use
|
||||
required: false
|
||||
default: "1.11"
|
||||
jfrog-token:
|
||||
description: Sets TF_TOKEN_schmalz_jfrog_io
|
||||
required: true
|
||||
aws-role-arn:
|
||||
description: If provided, runs aws-configure before validate
|
||||
required: false
|
||||
default: ""
|
||||
aws-profile:
|
||||
description: Profile if aws-role-arn given
|
||||
required: false
|
||||
default: stage
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- uses: schmalz/shared-actions/.github/actions/aws-configure@v1
|
||||
if: ${{ inputs.aws-role-arn != '' }}
|
||||
with:
|
||||
role-arn: ${{ inputs.aws-role-arn }}
|
||||
aws-profile: ${{ inputs.aws-profile }}
|
||||
|
||||
- uses: https://data.forgejo.org/actions/cache/restore@v4
|
||||
with:
|
||||
key: terraform-${{ hashFiles('**/.terraform.lock.hcl') }}
|
||||
path: ${{ inputs.terraform-dir }}/.terraform/providers
|
||||
|
||||
- name: Install Terraform
|
||||
shell: bash
|
||||
run: |
|
||||
TF_VERSION="${{ inputs.terraform-version }}"
|
||||
curl -fsSL "https://releases.hashicorp.com/terraform/${TF_VERSION}/terraform_${TF_VERSION}_linux_amd64.zip" -o /tmp/terraform.zip
|
||||
sudo unzip -o /tmp/terraform.zip -d /usr/local/bin
|
||||
rm /tmp/terraform.zip
|
||||
terraform version
|
||||
|
||||
- run: |
|
||||
export TF_TOKEN_schmalz_jfrog_io="${INPUT_JFROG_TOKEN}"
|
||||
export TF_WORKSPACE=stage
|
||||
terraform -chdir="${INPUT_TERRAFORM_DIR}" init -backend=false -no-color
|
||||
terraform -chdir="${INPUT_TERRAFORM_DIR}" fmt -check -recursive
|
||||
terraform -chdir="${INPUT_TERRAFORM_DIR}" validate
|
||||
shell: bash
|
||||
|
||||
- uses: https://data.forgejo.org/actions/cache/save@v4
|
||||
with:
|
||||
key: terraform-${{ hashFiles('**/.terraform.lock.hcl') }}
|
||||
path: ${{ inputs.terraform-dir }}/.terraform/providers
|
||||
73
.github/workflows/validate-shared-actions.yml
vendored
Normal file
73
.github/workflows/validate-shared-actions.yml
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
name: validate-shared-actions
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
validate-shared-actions:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
ACTIONLINT_VERSION: "1.7.8"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: https://code.forgejo.org/actions/checkout@v4
|
||||
|
||||
- name: Restore actionlint cache
|
||||
id: cache-actionlint
|
||||
uses: https://data.forgejo.org/actions/cache/restore@v4
|
||||
with:
|
||||
path: .cache/tools/actionlint
|
||||
key: actionlint-${{ runner.os }}-${{ env.ACTIONLINT_VERSION }}
|
||||
|
||||
- name: Install actionlint (pinned + checksum)
|
||||
if: ${{ steps.cache-actionlint.outputs.cache-hit != 'true' }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
VERSION="${ACTIONLINT_VERSION}"
|
||||
OS="linux"
|
||||
ARCH="amd64"
|
||||
BASE_URL="https://github.com/rhysd/actionlint/releases/download/v${VERSION}"
|
||||
TAR="actionlint_${VERSION}_${OS}_${ARCH}.tar.gz"
|
||||
CHECKSUMS="checksums.txt"
|
||||
|
||||
INSTALL_DIR=".cache/tools/actionlint/${VERSION}"
|
||||
mkdir -p "${INSTALL_DIR}"
|
||||
|
||||
curl -fsSL "${BASE_URL}/${TAR}" -o "/tmp/${TAR}"
|
||||
curl -fsSL "${BASE_URL}/${CHECKSUMS}" -o "/tmp/${CHECKSUMS}"
|
||||
|
||||
grep " ${TAR}$" "/tmp/${CHECKSUMS}" > "/tmp/actionlint-sha256.txt"
|
||||
(cd /tmp && sha256sum -c actionlint-sha256.txt)
|
||||
|
||||
tar -xzf "/tmp/${TAR}" -C "${INSTALL_DIR}" actionlint
|
||||
chmod +x "${INSTALL_DIR}/actionlint"
|
||||
|
||||
- name: Save actionlint cache
|
||||
if: ${{ steps.cache-actionlint.outputs.cache-hit != 'true' }}
|
||||
uses: https://data.forgejo.org/actions/cache/save@v4
|
||||
with:
|
||||
path: .cache/tools/actionlint
|
||||
key: actionlint-${{ runner.os }}-${{ env.ACTIONLINT_VERSION }}
|
||||
|
||||
- name: Lint workflows with actionlint
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
ACTIONLINT_BIN=".cache/tools/actionlint/${ACTIONLINT_VERSION}/actionlint"
|
||||
if [ ! -x "${ACTIONLINT_BIN}" ]; then
|
||||
echo "actionlint binary missing: ${ACTIONLINT_BIN}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if compgen -G ".github/workflows/*.yml" > /dev/null || compgen -G ".github/workflows/*.yaml" > /dev/null; then
|
||||
"${ACTIONLINT_BIN}" -color
|
||||
else
|
||||
echo "No workflow files found in .github/workflows; skipping actionlint workflow lint"
|
||||
fi
|
||||
50
.gitignore
vendored
50
.gitignore
vendored
|
|
@ -1,50 +0,0 @@
|
|||
# These are some examples of commonly ignored file patterns.
|
||||
# You should customize this list as applicable to your project.
|
||||
# Learn more about .gitignore:
|
||||
# https://www.atlassian.com/git/tutorials/saving-changes/gitignore
|
||||
|
||||
# Node artifact files
|
||||
node_modules/
|
||||
dist/
|
||||
|
||||
# Compiled Java class files
|
||||
*.class
|
||||
|
||||
# Compiled Python bytecode
|
||||
*.py[cod]
|
||||
|
||||
# Log files
|
||||
*.log
|
||||
|
||||
# Package files
|
||||
*.jar
|
||||
|
||||
# Maven
|
||||
target/
|
||||
dist/
|
||||
|
||||
# JetBrains IDE
|
||||
.idea/
|
||||
|
||||
# Unit test reports
|
||||
TEST*.xml
|
||||
|
||||
# Generated by MacOS
|
||||
.DS_Store
|
||||
|
||||
# Generated by Windows
|
||||
Thumbs.db
|
||||
|
||||
# Applications
|
||||
*.app
|
||||
*.exe
|
||||
*.war
|
||||
|
||||
# Large media files
|
||||
*.mp4
|
||||
*.tiff
|
||||
*.avi
|
||||
*.flv
|
||||
*.mov
|
||||
*.wmv
|
||||
|
||||
19
README.md
19
README.md
|
|
@ -6,7 +6,24 @@ Shared composite actions for Forgejo CI/CD pipelines.
|
|||
|
||||
| Action | Description |
|
||||
|--------|-------------|
|
||||
| | |
|
||||
| [aikido-full-scan](.github/actions/aikido-full-scan) | Run a full Aikido security scan (for nightly/scheduled runs) |
|
||||
| [aikido-pr-scan](.github/actions/aikido-pr-scan) | Run Aikido security scan on a PR in gating mode (fails on new vulnerabilities) |
|
||||
| [aws-configure](.github/actions/aws-configure) | Authenticate with AWS via OIDC |
|
||||
| [aws-lambda-update](.github/actions/aws-lambda-update) | Update Lambda function alias to a new version, optionally wait for provisioned concurrency |
|
||||
| [aws-s3-sync](.github/actions/aws-s3-sync) | Sync build artifacts to S3, clean up old versioned assets, optionally invalidate CloudFront |
|
||||
| [cloudfront-invalidate](.github/actions/cloudfront-invalidate) | Invalidate one or more CloudFront distributions |
|
||||
| [docker-build-push](.github/actions/docker-build-push) | Build Docker image and push to JFrog with semver tags (major, minor, patch) |
|
||||
| [helm-deploy](.github/actions/helm-deploy) | Deploy a service to Kubernetes via Helm over SSH |
|
||||
| [maven-build](.github/actions/maven-build) | Run Maven build — verify-only (PRs) or package+jib push (deploy) |
|
||||
| [playwright-e2e](.github/actions/playwright-e2e) | Run Playwright E2E tests with optional sharding, upload results to S3 |
|
||||
| [pnpm-build](.github/actions/pnpm-build) | Set up pnpm, authenticate JFrog npm registry, install deps, run scripts |
|
||||
| [publish-npm-package](.github/actions/publish-npm-package) | Build and publish npm package to JFrog Artifactory |
|
||||
| [publish-rust-crate](.github/actions/publish-rust-crate) | Build, test, and publish Rust crate to JFrog Cargo registry |
|
||||
| [rust-build](.github/actions/rust-build) | Run Rust CI — fmt, clippy, tests, optional cross-compilation |
|
||||
| [secrets-inject](.github/actions/secrets-inject) | Append a secrets file to a Java .properties file |
|
||||
| [terraform-apply](.github/actions/terraform-apply) | Full Terraform init + workspace + apply + output capture |
|
||||
| [terraform-module-publish](.github/actions/terraform-module-publish) | Zip a Terraform module and publish to JFrog Artifactory |
|
||||
| [terraform-validate](.github/actions/terraform-validate) | Validate Terraform code without backend (for PR checks) |
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue