Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
157 changes: 157 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
name: CodeQL

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '17 3 * * 0'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: codeql-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
analyze:
name: Analyze (${{ matrix.language }})
runs-on: ubuntu-24.04
timeout-minutes: 60
permissions:
contents: read
actions: read
security-events: write
strategy:
fail-fast: false
matrix:
include:
- language: actions
build-mode: none
- language: go
build-mode: manual
- language: java-kotlin
build-mode: manual
- language: python
build-mode: none

steps:
- name: Check out analysis source
uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5
with:
persist-credentials: false

- name: Record source identity
shell: bash
env:
EVENT_SHA: ${{ github.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
EVENT_REF: ${{ github.ref }}
run: |
set -Eeuo pipefail
printf 'event_sha=%s\npr_head_sha=%s\nevent_ref=%s\n' \
"$EVENT_SHA" "$PR_HEAD_SHA" "$EVENT_REF"
printf 'checked_out_sha=%s\nchecked_out_tree=%s\n' \
"$(git rev-parse HEAD)" "$(git rev-parse HEAD^{tree})"
test "$(git rev-parse HEAD)" = "$EVENT_SHA"

- name: Set up the production Go compiler
if: matrix.language == 'go'
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
# server/Dockerfile.web-compose-release ARTIFACT_HELPER_IMAGE.
go-version: '1.27.2'
check-latest: false
cache: false

- name: Set up the production Java compiler
if: matrix.language == 'java-kotlin'
uses: actions/setup-java@b6effb05e454b25005698d916606bdc6ffcbf961 # v5
with:
# server/Dockerfile TEMURIN_JDK25_VERSION.
distribution: temurin
java-version: '25.0.4+7.0.LTS'
check-latest: false

- name: Initialize CodeQL
uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
config: |
name: PastureStack complete extended analysis
queries:
- uses: security-extended
threat-models: local

- name: Build the Go console broker for analysis
if: matrix.language == 'go'
working-directory: server/console-broker
shell: bash
env:
CGO_ENABLED: '0'
GOOS: linux
GOARCH: amd64
GOTOOLCHAIN: local
run: |
set -Eeuo pipefail
test "$(go env GOVERSION)" = 'go1.27.2'
mkdir -p "$RUNNER_TEMP/codeql-go-build"
go build \
-mod=readonly \
-trimpath \
-buildvcs=false \
-ldflags='-s -w -buildid=' \
-o "$RUNNER_TEMP/codeql-go-build/pasturestack-console-broker" .

- name: Compile Java sources with the production Engine libraries
if: matrix.language == 'java-kotlin'
shell: bash
run: |
set -Eeuo pipefail
dockerfile=server/Dockerfile.web-compose-release
read_arg() {
local arg_name="$1"
local -a values
mapfile -t values < <(sed -n "s/^ARG ${arg_name}=//p" "$dockerfile" | sort -u)
test "${#values[@]}" -eq 1 || return 1
test -n "${values[0]}" || return 1
printf '%s' "${values[0]}"
}
release_base="$(read_arg ORCHESTRATION_ENGINE_RELEASE_BASE_URL)"
release_tag="$(read_arg ORCHESTRATION_ENGINE_RELEASE_TAG)"
artifact="$(read_arg ORCHESTRATION_ENGINE_ARTIFACT)"
expected_sha256="$(read_arg ORCHESTRATION_ENGINE_ARTIFACT_SHA256)"
test "$release_base" = 'https://github.com/PastureStack/orchestration-engine/releases/download'
[[ "$release_tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]
test "$artifact" = cattle.jar
[[ "$expected_sha256" =~ ^[0-9a-f]{64}$ ]]

build_root="$RUNNER_TEMP/codeql-java-build"
mkdir -p "$build_root/lib" "$build_root/classes"
archive="$build_root/cattle.jar"
curl --fail --silent --show-error --location \
--proto '=https' --proto-redir '=https' \
--retry 3 --connect-timeout 15 --max-time 600 \
--output "$archive" "$release_base/$release_tag/$artifact"
printf '%s %s\n' "$expected_sha256" "$archive" | sha256sum --check --strict
unzip -j -q "$archive" 'WEB-INF/lib/*.jar' -d "$build_root/lib"
compgen -G "$build_root/lib/*.jar" > /dev/null

# Compile every tracked Java source; the reviewed tree contains one
# PatchV1GlobalSubscribe.java and no Kotlin sources or Maven project.
# Failing on future Kotlin additions avoids silently omitting them.
mapfile -d '' -t kotlin_sources < <(git ls-files -z '*.kt' '*.kts')
test "${#kotlin_sources[@]}" -eq 0
mapfile -d '' -t java_sources < <(git ls-files -z '*.java')
test "${#java_sources[@]}" -gt 0
javac -cp "$build_root/lib/*" -d "$build_root/classes" "${java_sources[@]}"

- name: Analyze and upload CodeQL results
uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
with:
category: '/language:${{ matrix.language }}'
wait-for-processing: true
43 changes: 32 additions & 11 deletions .github/workflows/publish-current-server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,13 @@ jobs:
test "$(git -C source rev-parse HEAD)" = "$SOURCE_SHA"
test -z "$(git -C source status --short)"

declared_release="$(sed -n 's/.*org.opencontainers.image.version="\([^"]*\)".*/\1/p' \
source/server/Dockerfile.web-compose-release)"
declared_release="$(sed -n 's/^ARG SERVER_RELEASE_TAG=//p' \
source/server/Dockerfile.web-compose-release | sort -u)"
test "$declared_release" = "$RELEASE_TAG"
host_api_version="$(sed -n 's/^ARG HOST_API_VERSION=//p' \
source/server/Dockerfile.web-compose-release | sort -u)"
[[ "$host_api_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]
printf 'HOST_API_VERSION=%s\n' "$host_api_version" >>"$GITHUB_ENV"
release_notes="source/docs/releases/server-${RELEASE_TAG#v}.md"
test -f "$release_notes"
test -s "$release_notes"
Expand Down Expand Up @@ -340,15 +344,32 @@ jobs:
docker export --output "$RUNNER_TEMP/server-rootfs.tar" "$CANDIDATE_NAME"
tar --no-same-owner -xf "$RUNNER_TEMP/server-rootfs.tar" -C "$rootfs"
test "$(readlink "$rootfs/usr/share/cattle/artifacts/host-api.tar.gz")" = \
host-api-0.38.4.tar.gz
"host-api-${HOST_API_VERSION}.tar.gz"
grep -Fx \
'export CATTLE_AGENT_PACKAGE_HOST_API_URL=/usr/share/cattle/artifacts/host-api-0.38.4.tar.gz' \
"export CATTLE_AGENT_PACKAGE_HOST_API_URL=/usr/share/cattle/artifacts/host-api-${HOST_API_VERSION}.tar.gz" \
"$rootfs/usr/share/cattle/env_vars" >/dev/null
cp "$rootfs/usr/share/cattle/artifacts/host-api-0.38.4.tar.gz" \
"$evidence/host-api-0.38.4.tar.gz"
bash source/scripts/check-server-host-api-package.sh \
"$evidence/host-api-0.38.4.tar.gz" |
tee "$evidence/host-api-package-check.txt"
cp "$rootfs/usr/share/cattle/artifacts/host-api-${HOST_API_VERSION}.tar.gz" \
"$evidence/host-api-${HOST_API_VERSION}.tar.gz"
host_default() {
sed -n "s/^ARG ${1}=//p" source/server/Dockerfile.web-compose-release | sort -u
}
if [[ "$(host_default HOST_API_PACKAGE_MODE)" == producer ]]; then
printf '%s %s\n' "$(host_default HOST_API_ARCHIVE_SHA256)" \
"$evidence/host-api-${HOST_API_VERSION}.tar.gz" | sha256sum -c -
bash source/server/artifacts/verify-host-api-package.sh \
"$evidence/host-api-${HOST_API_VERSION}.tar.gz" \
"$(host_default HOST_API_PACKAGE_ID)" \
"$(host_default HOST_API_BINARY_SHA256)" \
"$(host_default HOST_API_APPLY_SHA256)" \
"$(host_default HOST_API_COMMIT)" |
tee "$evidence/host-api-package-check.txt"
else
test "$(host_default HOST_API_PACKAGE_MODE)" = legacy-repair
test "$HOST_API_VERSION" = 0.38.4
bash source/scripts/check-server-host-api-package.sh \
"$evidence/host-api-${HOST_API_VERSION}.tar.gz" |
tee "$evidence/host-api-package-check.txt"
fi
printf 'SERVER_CANDIDATE_SMOKE_OK release=%s first_attempts=%s restart_attempts=%s catalog_attempts=%s first_contract_attempts=%s restart_contract_attempts=%s http=200 body=pong public_origin=https://stack.example.test private_api_cache=no-store\n' \
"$RELEASE_TAG" "$first_attempts" "$restart_attempts" "$catalog_attempts" \
"$first_contract_attempts" "$restart_contract_attempts" |
Expand Down Expand Up @@ -560,7 +581,7 @@ jobs:
build.log \
candidate.log \
candidate-smoke.txt \
host-api-0.38.4.tar.gz \
"host-api-${HOST_API_VERSION}.tar.gz" \
host-api-package-check.txt \
image-inspect.txt \
mfa-policy-api-smoke.txt \
Expand Down Expand Up @@ -590,7 +611,7 @@ jobs:
"$evidence/build.log" \
"$evidence/candidate.log" \
"$evidence/candidate-smoke.txt" \
"$evidence/host-api-0.38.4.tar.gz" \
"$evidence/host-api-${HOST_API_VERSION}.tar.gz" \
"$evidence/host-api-package-check.txt" \
"$evidence/image-inspect.txt" \
"$evidence/mfa-policy-api-smoke.txt" \
Expand Down
74 changes: 64 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,62 @@ Rancher 1.6 ecosystem. It is not affiliated with Rancher Labs or SUSE.
This fork of [`rancher/rancher`](https://github.com/rancher/rancher) preserves
upstream history, authorship, licenses, and notices.

## Current release
## Current source

Server `v1.6.519` is an unpublished candidate, packaging Web Console `1.6.181`
and Orchestration Engine `v0.183.335`. API Keys support full, custom and closed
policies, optional expiry, and key-scoped durable audit records. Their permissions
remain bounded by the owner's current role and environment access. Delegated
terminal/log access requires the verified Host API audit capability and the
compatible Linux Node Agent lifecycle.
Custom Key Project targets share the normal API's live membership checks;
membership never bypasses Key rules or unrelated resource authorization.

[Server v1.6.518](https://github.com/PastureStack/server/releases/tag/v1.6.518)
includes Web Console `1.6.180` and Orchestration Engine `v0.183.333`.
The console supports OIDC, TOTP and passkeys, role-aware resource operations,
container resource/hardware settings, and movable terminal/log windows.
Hardware options require compatible node software and actual host capabilities;
GPU device access is not exclusive GPU allocation.
GPU device access is not exclusive GPU allocation. Audit queries and exports
cover retained records with environment-aware access and bounded pagination.
Explicit date bounds remain attached to every audit page, so an older interval
does not scan newer records first. Oversized queries retain the console filters
and offer explicit narrowing or retry. Export failures are translated on the
page instead of downloaded as error files. An export failure keeps successful
query results intact; scan and export limits are retained.
The Key modal owns initial focus and yields to keyboard or pointer interaction.
Audit export closes its own menu before locking the request, allowing consecutive
JSON, CSV and XLSX downloads without leaving a disabled menu open.
Key scope choices use the viewer's authorized environment list. Environment,
stack and resource selectors close before dependent loading or verification.
See the [candidate release note](docs/releases/server-1.6.519.md) for exact
component identities and verification boundaries. A version or packaged feature
does not establish that every resource/role/hardware combination has been tested.

## API Keys in the source candidate

Choose allow-by-default with deny exceptions, or deny-by-default with allow
exceptions, with optional expiry. Without exceptions these retain full or closed
access. Search for resource names; the editor and reviewed changes include a
resource-by-operation policy matrix, not an extra grant of authority. The maximum access
is always the Key owner's current account/environment RBAC; a Key never grants
an additional role. Existing legacy Keys are not automatically narrowed on upgrade.
New Key secrets are shown once at creation and are not returned by later lists or
details. Per-Key audit separates authorization, the HTTP response and any later
job/stream completion. Environment-Key audit rechecks live Engine access in
Engine-verified project contexts; a caller-supplied project header is not a grant.
Open a Key's audit from its action menu; the close control follows the audit
filters, results and details, below the audit block.
Scope options and unselected hints use readable light/dark theme text, including
keyboard highlighting; narrow layouts keep the matrix in its own scroll region.
Errors use the existing API status/code and console error
handling. See the [API Key guide](docs/api-keys.md) for policy and audit contracts.

## Current release

The current release packages Metadata-driven CNI configuration migration fixes
and all-retained-time audit queries and exports. Authentication and
authorization contracts are retained. See the
[release note](docs/releases/server-1.6.518.md) for component identities,
verification results, and known limits. A published image is not a claim that
every resource/role/hardware combination has been tested.
The currently downloadable [Server v1.6.518](https://github.com/PastureStack/server/releases/tag/v1.6.518)
includes Web Console `1.6.180` and Orchestration Engine `v0.183.333`.
The quick-start examples below use this published image until the candidate is
verified and separately released. Its exact artifact identity and verification
boundaries are recorded in the [published release note](docs/releases/server-1.6.518.md).

## Quick start

Expand Down Expand Up @@ -78,6 +119,11 @@ by default and requires explicit apply/rollback. Keep the previous image and
backup: after a database migration, rollback may require restoring matching data,
not merely selecting an older image tag.

After using API Key policy or expiry, do not downgrade directly to a
policy-unaware Engine: an older version can treat a restricted or expired Key
as full access. Follow the [API Key rollback safety guide](docs/upgrades/api-key-policy-rollback.md)
before any downgrade or database restore.

[GitHub Releases](https://github.com/PastureStack/server/releases) contain
versioned assets, SHA-256 checksums, and release records. Built-in templates come
from pinned [`catalog-templates`](https://github.com/PastureStack/catalog-templates)
Expand All @@ -97,6 +143,14 @@ Runtime, database migration, registration, backup/restore, and upgrade validatio
use isolated hosts. Publication is a separate, manually dispatched workflow.
See [ORIGIN.md](ORIGIN.md) and [SECURITY.md](SECURITY.md).

The component candidate build uses the same release Dockerfile and verification
gates. `server/build-component-candidate.sh` requires actual component commits
and SHA-256 values; it does not publish or deploy. Set
`PASTURESTACK_COMPONENT_ARTIFACT_DIR` to an isolated directory with the five
component assets for an unpublished candidate. Without it, the same hashes
verify the versioned HTTPS release assets. The current published release remains
`v1.6.518` until a candidate is verified and separately released.

## Language and licensing

The console packages thirteen locales, including Traditional Chinese for Taiwan.
Expand Down
Loading