-
Notifications
You must be signed in to change notification settings - Fork 0
ci: serialize Crossplane validation #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,10 +12,12 @@ on: | |
| paths: | ||
| - ".github/workflows/on-pr.yaml" | ||
| - ".gitops/**" | ||
| - "Makefile" | ||
| - "apis/**" | ||
| - "examples/**" | ||
| - "tests/**" | ||
| - "functions/**" | ||
| - "scripts/**" | ||
| - "upbound.yaml" | ||
|
|
||
| permissions: | ||
|
|
@@ -27,31 +29,51 @@ permissions: | |
|
|
||
| jobs: | ||
| validate: | ||
| uses: unbounded-tech/workflows-crossplane/.github/workflows/validate.yaml@v3.0.0 | ||
| with: | ||
| examples: | | ||
| [ | ||
| { "example": "examples/crossplanestacks/minimal.yaml", "api_path": "apis/crossplanestacks" }, | ||
| { "example": "examples/crossplanestacks/standard.yaml", "api_path": "apis/crossplanestacks" }, | ||
| { "example": "examples/crossplanestacks/full.yaml", "api_path": "apis/crossplanestacks" }, | ||
| { "example": "examples/awsproviderstacks/minimal.yaml", "api_path": "apis/awsproviderstacks" }, | ||
| { "example": "examples/awsproviderstacks/full.yaml", "api_path": "apis/awsproviderstacks" }, | ||
| { "example": "examples/functionsstacks/minimal.yaml", "api_path": "apis/functionsstacks" }, | ||
| { "example": "examples/functionsstacks/full.yaml", "api_path": "apis/functionsstacks" }, | ||
| { "example": "examples/githubproviderstacks/minimal.yaml", "api_path": "apis/githubproviderstacks" }, | ||
| { "example": "examples/githubproviderstacks/full.yaml", "api_path": "apis/githubproviderstacks" }, | ||
| { "example": "examples/helmproviderstacks/minimal.yaml", "api_path": "apis/helmproviderstacks" }, | ||
| { "example": "examples/helmproviderstacks/full.yaml", "api_path": "apis/helmproviderstacks" }, | ||
| { "example": "examples/kubernetesproviderstacks/minimal.yaml", "api_path": "apis/kubernetesproviderstacks" }, | ||
| { "example": "examples/kubernetesproviderstacks/full.yaml", "api_path": "apis/kubernetesproviderstacks" }, | ||
| { "example": "examples/listmonkproviderstacks/minimal.yaml", "api_path": "apis/listmonkproviderstacks" }, | ||
| { "example": "examples/listmonkproviderstacks/full.yaml", "api_path": "apis/listmonkproviderstacks" }, | ||
| { "example": "examples/openpanelproviderstacks/minimal.yaml", "api_path": "apis/openpanelproviderstacks" }, | ||
| { "example": "examples/openpanelproviderstacks/full.yaml", "api_path": "apis/openpanelproviderstacks" }, | ||
| { "example": "examples/zitadelproviderstacks/minimal.yaml", "api_path": "apis/zitadelproviderstacks" }, | ||
| { "example": "examples/zitadelproviderstacks/full.yaml", "api_path": "apis/zitadelproviderstacks" } | ||
| ] | ||
| error_on_missing_schemas: true | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Cache crossplane | ||
| uses: actions/cache@v5 | ||
| with: | ||
| path: | | ||
| ~/.crossplane/cache | ||
| ~/.up/cache | ||
| ~/.up/build-cache | ||
| key: ${{ runner.os }}-crossplane-${{ hashFiles('**/upbound.yaml','**/definition.yaml') }}- | ||
|
|
||
| - name: Install up | ||
| env: | ||
| UP_VERSION: v0.46.0 | ||
| run: | | ||
| set -euo pipefail | ||
| curl --fail --location --retry 5 --retry-all-errors --retry-delay 5 \ | ||
| "https://cli.upbound.io/stable/${UP_VERSION}/bin/linux_amd64/up" \ | ||
| --output up | ||
| chmod +x up | ||
| sudo mv up /usr/local/bin/up | ||
| up version | ||
|
|
||
| - name: Install Crossplane CLI | ||
| run: | | ||
| curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh \ | ||
| | XP_VERSION=v2.0.2 sh | ||
|
|
||
|
Comment on lines
+58
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Locate and print the referenced workflow section
FILE=".github/workflows/on-pr.yaml"
echo "== File: $FILE =="
if [ -f "$FILE" ]; then
nl -ba "$FILE" | sed -n '40,90p'
else
echo "Missing: $FILE"
exit 1
fi
# Search for crossplane install usage elsewhere in workflows
echo
echo "== Search: crossplane install usage =="
rg -n "crossplane.*install|install\\.sh|XP_VERSION|raw\\.githubusercontent\\.com/crossplane/crossplane" .github/workflows || true
# Search for any other pinned version usage (v2.0.2 etc.) in repo
echo
echo "== Search: XP_VERSION pin =="
rg -n "XP_VERSION|v2\.0\.2|crossplane.*v[0-9]+\.[0-9]+\.[0-9]+" .github/workflows || trueRepository: hops-ops/aws-crossplane-stack Length of output: 175 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE=".github/workflows/on-pr.yaml"
echo "== File: $FILE =="
if [ -f "$FILE" ]; then
awk 'NR>=40 && NR<=90 {printf "%d\t%s\n", NR, $0}' "$FILE"
else
echo "Missing: $FILE"
exit 1
fi
echo
echo "== Search: crossplane install usage =="
rg -n "crossplane.*install|install\\.sh|XP_VERSION|raw\\.githubusercontent\\.com/crossplane/crossplane" .github/workflows || true
echo
echo "== Search: XP_VERSION pin =="
rg -n "XP_VERSION|v2\\.0\\.2|crossplane.*v[0-9]+\\.[0-9]+\\.[0-9]+" .github/workflows || trueRepository: hops-ops/aws-crossplane-stack Length of output: 3131 🌐 Web query:
💡 Result: To install the Crossplane CLI version v2.0.2, you can use the official Crossplane installation script with an environment variable to specify the version [1][2]. The installation script is located at: https://raw.githubusercontent.com/crossplane/crossplane/main/install.sh Run the following command in your terminal to download and install the v2.0.2 binary: curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/main/install.sh" | XP_VERSION=v2.0.2 sh After running this command, the script will download the binary, which you can then move to your local path (e.g., /usr/local/bin) to use the crossplane CLI [3][4]. Important Installation Notes: 1. Crossplane CLI vs. Crossplane Control Plane: The install script described above is for the Crossplane CLI (command-line tool) [1][2]. The Crossplane control plane itself is installed into a Kubernetes cluster using Helm [5][6]. 2. Version Compatibility: For versions prior to v2.3.0, the installation script identifies the binary as "crank" and renames it to "crossplane" during the installation process [4][7]. 3. Manual Installation: If you prefer not to use the shell script, you can manually download the binary from the official release repository [1][2]. For v2.0.2, you would look for the binary at https://releases.crossplane.io/stable/v2.0.2/bin/ [1][4]. Citations:
🌐 Web query:
💡 Result: Crossplane’s recommended one-liner to install the Crossplane CLI is: curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/main/install.sh" | sh [1] Security/pinning notes (based on the install script and docs): 1) The command above downloads whatever install.sh exists at the referenced URL and then executes it, so it is not “pinned” to a specific commit of the script. The script itself supports pinning the CLI version you install, via XP_VERSION and XP_CHANNEL environment variables (these choose which artifact to download) [1][2]. 2) The install.sh script downloads a platform-specific CLI binary using curl with flags that fail on HTTP errors and follow redirects (curl -sfL...). It does not, in the portions shown, include an additional integrity check such as verifying a checksum before executing the result [3]. 3) Crossplane’s docs also provide a manual alternative that avoids running the downloaded shell script: you can download the CLI binary directly from the releases repository for your channel/version [1]. Recommended safer patterns you can use: A) Pin the CLI artifact version (still runs unpinned install.sh): XP_VERSION=v1.20.0 curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/main/install.sh" | sh [1] B) Pin the install script itself (unpinned CLI artifact risk remains unless you also pin XP_VERSION/XP_CHANNEL): - Prefer using a raw URL that targets a specific crossplane/crossplane commit hash for install.sh, rather than the moving /main/ (or /master/) path. The exact content of install.sh can be verified via the raw file at that commit [4]. C) Avoid executing install.sh (most “no-script” approach): - Manually download the CLI binary from the releases repository for your desired channel/version (docs call out that the release repo names the CLI binary “crank”) [1]. Citations:
🌐 Web query:
💡 Result: The URL you provided (raw.githubusercontent.com/crossplane/crossplane/v2.0.2/install.sh) is an installation script for the Crossplane CLI binary (not the Crossplane Helm chart / controller itself). The script’s job is to download the appropriate CLI binary for your OS/CPU and place it as a local executable (typically into /usr/local/bin via the post-install instructions). It supports selecting release “channel” and “version” via XP_CHANNEL and XP_VERSION environment variables, and handles “older” versions that used the crank binary/artifacts vs newer versions that use crossplane/crossplane-cli artifacts. Key behaviors (from the script logic visible in the repository’s install.sh): 1) Default environment variables - XP_CHANNEL defaults to “stable”. - XP_VERSION defaults to “current”. - BIN defaults to “crossplane”. [1] 2) OS/architecture detection - The script uses uname -s and uname -m to build the OS and ARCH/OS_ARCH values used in the download URL. [1] 3) Artifact URL construction - It constructs a download URL of the form: https://<url_host>/<XP_CHANNEL>/<XP_VERSION>/<url_dir>/<OS_ARCH>/<url_file> [1] - For “compressed” downloads (COMPRESSED=true) it downloads a tarball (crossplane-cli.tar.gz); otherwise it downloads the binary directly. [1] 4) Compatibility logic for older CLI releases - If XP_VERSION is not “current”, it parses the major/minor version. - For versions earlier than 2.3 (major==2 and minor<3, or major<2), it switches to: - url_host = releases.crossplane.io - bundle_name = crank.tar.gz - BIN = crank Otherwise it uses: - url_host = cli.crossplane.io - bundle_name = crossplane-cli.tar.gz - BIN name “crossplane” [1] 5) Download, unpack, and rename - It downloads with curl -sfL and exits with an error if the requested version/channel artifacts are missing. [1] - If a tarball was downloaded, it unpacks it with tar xzf and then removes the sha256 + tarball. [1] - If the downloaded binary name is not “crossplane” (e.g., crank for older versions), it renames it to crossplane. [1] 6) Finalization - It chmod +x crossplane. [1] - It prints instructions to move it to /usr/local/bin and run crossplane --help. [1] How this relates to official documentation (current mechanism) - Crossplane’s CLI docs describe using an install script from the raw GitHub URL, e.g. curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/main/install.sh" | sh, and explain that the script detects CPU architecture and downloads the latest stable release. [2] - The docs also describe XP_CHANNEL and XP_VERSION variables for selecting other CLI versions/branches, matching the same variables used inside install.sh. [2] Note on “today’s” date / version targeting - Your request specifies v2.0.2, but the web results I could retrieve in the first search round show the install.sh content from the repository’s master branch (URL ending in /crossplane/master/install.sh). The code patterns above are therefore grounded in that retrieved install.sh content; the same script template is what the docs refer to for installing any version by pinning XP_VERSION/XP_CHANNEL or by pointing at a release-specific install.sh URL. [1][2] Citations:
🌐 Web query:
💡 Result: The URL raw.githubusercontent.com/crossplane/crossplane/v2.0.2/install.sh does not exist (it returns 404), while the install script does exist for other paths/tags (e.g., master has https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh). [1] What I found: 1) Crossplane’s official docs reference the installer at raw.githubusercontent.com/crossplane/crossplane/main/install.sh / install.sh from the repository’s main branch (not v2.0.2). [2] 2) I could locate the repository’s install.sh content on master (but not on the v2.0.2 tag path). [1] So for v2.0.2 specifically, expect 404 at that raw.githubusercontent.com path. Citations:
🌐 Web query:
💡 Result: There is no official recommendation to pin the Crossplane install.sh script to a specific commit hash, and the script is intended to be fetched from the main branch to ensure the most recent installation logic is used [1][2][3]. For production or reproducible environments where you require a consistent CLI version, the official documentation instead recommends pinning the version of the Crossplane CLI binary itself using the XP_VERSION environment variable [3][4]. To install a specific version, use: curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/main/install.sh" | XP_VERSION=v1.20.0 sh This ensures that regardless of updates to the install.sh script, you receive the specific binary version desired [3][4]. While the script is currently maintained in the main branch of the Crossplane repository [1][2], security discussions have noted the risks of piping directly to shell and have proposed future improvements for integrity verification [5]. Always prefer fetching official release versions as documented in the Crossplane CLI reference [3][4]. Citations:
Avoid executing an unpinned Crossplane installer via
🤖 Prompt for AI Agents |
||
| - name: Docker login to GHCR | ||
| uses: docker/login-action@v3.7.0 | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.actor }} | ||
| password: ${{ github.token }} | ||
|
|
||
| - name: Build with up | ||
| uses: upbound/action-up-project@v1.1.2 | ||
| with: | ||
| skip-login-check: true | ||
|
|
||
| - name: Validate all examples | ||
| run: scripts/ci-validate-all.sh | ||
|
|
||
| test: | ||
| uses: unbounded-tech/workflows-crossplane/.github/workflows/test.yaml@v3.0.0 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,9 +8,11 @@ on: | |
| - ".github/workflows/on-push-main.yaml" | ||
| - ".github/workflows/on-version-tagged.yaml" | ||
| - ".gitops/**" | ||
| - "Makefile" | ||
| - "apis/**" | ||
| - "examples/**" | ||
| - "functions/**" | ||
| - "scripts/**" | ||
| - "tests/**" | ||
| - "upbound.yaml" | ||
|
|
||
|
|
@@ -23,31 +25,51 @@ permissions: | |
|
|
||
| jobs: | ||
| validate: | ||
| uses: unbounded-tech/workflows-crossplane/.github/workflows/validate.yaml@v3.0.0 | ||
| with: | ||
| examples: | | ||
| [ | ||
| { "example": "examples/crossplanestacks/minimal.yaml", "api_path": "apis/crossplanestacks" }, | ||
| { "example": "examples/crossplanestacks/standard.yaml", "api_path": "apis/crossplanestacks" }, | ||
| { "example": "examples/crossplanestacks/full.yaml", "api_path": "apis/crossplanestacks" }, | ||
| { "example": "examples/awsproviderstacks/minimal.yaml", "api_path": "apis/awsproviderstacks" }, | ||
| { "example": "examples/awsproviderstacks/full.yaml", "api_path": "apis/awsproviderstacks" }, | ||
| { "example": "examples/functionsstacks/minimal.yaml", "api_path": "apis/functionsstacks" }, | ||
| { "example": "examples/functionsstacks/full.yaml", "api_path": "apis/functionsstacks" }, | ||
| { "example": "examples/githubproviderstacks/minimal.yaml", "api_path": "apis/githubproviderstacks" }, | ||
| { "example": "examples/githubproviderstacks/full.yaml", "api_path": "apis/githubproviderstacks" }, | ||
| { "example": "examples/helmproviderstacks/minimal.yaml", "api_path": "apis/helmproviderstacks" }, | ||
| { "example": "examples/helmproviderstacks/full.yaml", "api_path": "apis/helmproviderstacks" }, | ||
| { "example": "examples/kubernetesproviderstacks/minimal.yaml", "api_path": "apis/kubernetesproviderstacks" }, | ||
| { "example": "examples/kubernetesproviderstacks/full.yaml", "api_path": "apis/kubernetesproviderstacks" }, | ||
| { "example": "examples/listmonkproviderstacks/minimal.yaml", "api_path": "apis/listmonkproviderstacks" }, | ||
| { "example": "examples/listmonkproviderstacks/full.yaml", "api_path": "apis/listmonkproviderstacks" }, | ||
| { "example": "examples/openpanelproviderstacks/minimal.yaml", "api_path": "apis/openpanelproviderstacks" }, | ||
| { "example": "examples/openpanelproviderstacks/full.yaml", "api_path": "apis/openpanelproviderstacks" }, | ||
| { "example": "examples/zitadelproviderstacks/minimal.yaml", "api_path": "apis/zitadelproviderstacks" }, | ||
| { "example": "examples/zitadelproviderstacks/full.yaml", "api_path": "apis/zitadelproviderstacks" } | ||
| ] | ||
| error_on_missing_schemas: true | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v6 | ||
|
Comment on lines
+30
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the workflow file around the referenced lines
FILE=".github/workflows/on-push-main.yaml"
echo "== File: $FILE =="
if [ -f "$FILE" ]; then
nl -ba "$FILE" | sed -n '1,120p'
else
echo "Missing: $FILE"
fi
# Also list other workflows that might share the same patterns (for comparison)
echo
echo "== Other workflows referencing this file (if any) =="
fd .github/workflows -t f | sortRepository: hops-ops/aws-crossplane-stack Length of output: 182 🏁 Script executed: #!/bin/bash
set -euo pipefail
FILE=".github/workflows/on-push-main.yaml"
echo "== File: $FILE =="
if [ -f "$FILE" ]; then
# Print with line numbers without nl
awk '{printf "%d\t%s\n", NR, $0}' "$FILE" | sed -n '1,140p'
else
echo "Missing: $FILE"
fi
echo
echo "== Repo .github/workflows files =="
fd ".github/workflows" -t f | sort || trueRepository: hops-ops/aws-crossplane-stack Length of output: 3891 🌐 Web query:
💡 Result: For actions/checkout@v6, the persist-credentials input’s “default value” is effectively true (enabled) when you don’t set it in your workflow, because the action.yml defines persist-credentials with a default of an empty string (meaning use the action’s built-in default behavior) and the v6 README describes that credentials are persisted unless you opt out with persist-credentials: false [1][2]. What the action does: - The auth token is persisted in the local git config so that subsequent authenticated git commands work in the job; the token is removed during post-job cleanup. You can disable this by setting persist-credentials: false [2]. So if you write: - uses: actions/checkout@v6 (without a persist-credentials key), it behaves as “persist-credentials enabled” [1][2]. Citations:
Harden checkout credentials and pin third-party actions to immutable refs
🧰 Tools🪛 zizmor (1.25.2)[warning] 30-31: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) [error] 31-31: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
|
|
||
| - name: Cache crossplane | ||
| uses: actions/cache@v5 | ||
| with: | ||
| path: | | ||
| ~/.crossplane/cache | ||
| ~/.up/cache | ||
| ~/.up/build-cache | ||
| key: ${{ runner.os }}-crossplane-${{ hashFiles('**/upbound.yaml','**/definition.yaml') }}- | ||
|
|
||
| - name: Install up | ||
| env: | ||
| UP_VERSION: v0.46.0 | ||
| run: | | ||
| set -euo pipefail | ||
| curl --fail --location --retry 5 --retry-all-errors --retry-delay 5 \ | ||
| "https://cli.upbound.io/stable/${UP_VERSION}/bin/linux_amd64/up" \ | ||
| --output up | ||
| chmod +x up | ||
| sudo mv up /usr/local/bin/up | ||
| up version | ||
|
|
||
| - name: Install Crossplane CLI | ||
| run: | | ||
| curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh \ | ||
| | XP_VERSION=v2.0.2 sh | ||
|
Comment on lines
+54
to
+57
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Show the referenced workflow lines
sed -n '1,120p' .github/workflows/on-push-main.yaml | nl -ba | sed -n '40,80p'
# Search for other uses of the Crossplane install script URL (master or otherwise)
rg -n "crossplane/crossplane/(master|main)/install\.sh|XP_VERSION|Install Crossplane CLI|install\.sh \\\"" -S .github/workflows . || true
# Search for any other Crossplane installer/provenance handling
rg -n "crossplane.*install\.sh|XP_VERSION=" -S .github/workflows . || trueRepository: hops-ops/aws-crossplane-stack Length of output: 116 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "=== Workflow snippet around lines 50-70 ==="
# Use sed with explicit range; no line-number printer needed
sed -n '45,75p' .github/workflows/on-push-main.yaml
echo
echo "=== Search for Crossplane installer URL patterns ==="
rg -n "crossplane/crossplane/.*/install\.sh|XP_VERSION=|Install Crossplane CLI|XP_VERSION=" .github/workflows -S || true
echo
echo "=== Search repo for 'install.sh' invocations ==="
rg -n "install\.sh" . -S || trueRepository: hops-ops/aws-crossplane-stack Length of output: 1748 Pin the Crossplane installer source instead of using the moving The workflow downloads - name: Install Crossplane CLI
run: |
curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh \
| XP_VERSION=v2.0.2 shUse a pinned commit/tag for the installer URL (and ideally verify provenance, e.g., checksum/signature) to keep branch-to-branch CI deterministic and safer. 🤖 Prompt for AI Agents |
||
|
|
||
| - name: Docker login to GHCR | ||
| uses: docker/login-action@v3.7.0 | ||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.actor }} | ||
| password: ${{ github.token }} | ||
|
|
||
| - name: Build with up | ||
| uses: upbound/action-up-project@v1.1.2 | ||
| with: | ||
| skip-login-check: true | ||
|
|
||
| - name: Validate all examples | ||
| run: scripts/ci-validate-all.sh | ||
|
|
||
| test: | ||
| uses: unbounded-tech/workflows-crossplane/.github/workflows/test.yaml@v3.0.0 | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| crossplane_bin="${CROSSPLANE_BIN:-./crossplane}" | ||
| if [ ! -x "$crossplane_bin" ]; then | ||
| crossplane_bin="$(command -v crossplane)" | ||
| fi | ||
|
|
||
| configuration_from_upbound() { | ||
| local api_dir="$1" | ||
| local output_file="${api_dir}/configuration.yaml" | ||
|
|
||
| mkdir -p "$api_dir" | ||
|
|
||
| python3 - upbound.yaml "$output_file" <<'PY' | ||
| import re | ||
| import sys | ||
| import tempfile | ||
|
|
||
| try: | ||
| import yaml | ||
| except Exception: | ||
| target = f"{tempfile.gettempdir()}/aws-crossplane-stack-pyyaml" | ||
| sys.path.insert(0, target) | ||
| try: | ||
| import yaml | ||
| except Exception: | ||
| import subprocess | ||
| subprocess.check_call( | ||
| [sys.executable, "-m", "pip", "install", "--quiet", "--target", target, "PyYAML"] | ||
| ) | ||
| import yaml | ||
|
|
||
| in_file, out_file = sys.argv[1], sys.argv[2] | ||
|
|
||
| with open(in_file, "r", encoding="utf-8") as f: | ||
| project = yaml.safe_load(f) or {} | ||
|
|
||
| metadata = project.get("metadata") or {} | ||
| spec = project.get("spec") or {} | ||
|
|
||
| name = metadata.get("name") | ||
| if not name: | ||
| raise SystemExit("upbound.yaml is missing metadata.name") | ||
|
|
||
| maintainer = spec.get("maintainer", "") | ||
| if isinstance(maintainer, str): | ||
| maintainer = re.sub(r"\s*<[^>]+>\s*$", "", maintainer).strip() | ||
|
|
||
| annotations = { | ||
| "meta.crossplane.io/maintainer": maintainer, | ||
| "meta.crossplane.io/source": spec.get("source", ""), | ||
| "meta.crossplane.io/description": spec.get("description", ""), | ||
| } | ||
|
|
||
| depends_on = [] | ||
| for dep in spec.get("dependsOn") or []: | ||
| if not isinstance(dep, dict): | ||
| continue | ||
|
|
||
| kind = str(dep.get("kind", "")).strip().lower() | ||
| package = dep.get("package") | ||
| version = dep.get("version") | ||
| if not package: | ||
| continue | ||
|
|
||
| if kind == "provider": | ||
| item = {"provider": package} | ||
| elif kind == "function": | ||
| item = {"function": package} | ||
| elif kind == "configuration": | ||
| item = {"configuration": package} | ||
| else: | ||
| continue | ||
|
|
||
| if version is not None: | ||
| item["version"] = version | ||
| depends_on.append(item) | ||
|
|
||
| output = { | ||
| "apiVersion": "meta.pkg.crossplane.io/v1alpha1", | ||
| "kind": "Configuration", | ||
| "metadata": { | ||
| "name": name, | ||
| "annotations": {k: v for k, v in annotations.items() if v}, | ||
| }, | ||
| "spec": { | ||
| "dependsOn": depends_on, | ||
| }, | ||
| } | ||
|
|
||
| with open(out_file, "w", encoding="utf-8") as f: | ||
| yaml.safe_dump(output, f, sort_keys=False) | ||
|
|
||
| print(f"Wrote {out_file}") | ||
| PY | ||
| } | ||
|
|
||
| render_with_retry() { | ||
| local attempt=1 | ||
| local max_attempts="${RENDER_RETRIES:-3}" | ||
| local retry_delay="${RENDER_RETRY_DELAY_SECONDS:-5}" | ||
| local status=0 | ||
| local output | ||
|
|
||
| output="$(mktemp)" | ||
| while true; do | ||
| if up composition render "$@" >"$output"; then | ||
| cat "$output" | ||
| rm -f "$output" | ||
| return 0 | ||
| fi | ||
|
|
||
| status=$? | ||
| rm -f "$output" | ||
| if [ "$attempt" -ge "$max_attempts" ]; then | ||
| return "$status" | ||
| fi | ||
|
Comment on lines
+108
to
+118
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Line 114 captures Suggested fix while true; do
- if up composition render "$@" >"$output"; then
+ if up composition render "$@" >"$output"; then
cat "$output"
rm -f "$output"
return 0
+ else
+ status=$?
fi
-
- status=$?
rm -f "$output"
if [ "$attempt" -ge "$max_attempts" ]; then
return "$status"
fi🤖 Prompt for AI Agents |
||
|
|
||
| echo "Render attempt ${attempt}/${max_attempts} failed; retrying in ${retry_delay}s..." >&2 | ||
| sleep "$retry_delay" | ||
| attempt=$((attempt + 1)) | ||
| output="$(mktemp)" | ||
| done | ||
| } | ||
|
|
||
| while IFS= read -r entry; do | ||
| [ -n "$entry" ] || continue | ||
|
|
||
| example="${entry%%::*}" | ||
| observed="${entry#*::}" | ||
| api_dir="$(awk -F/ '{print "apis/" $2}' <<<"$example")" | ||
| composition="${api_dir}/composition.yaml" | ||
| definition="${api_dir}/definition.yaml" | ||
| render_args=(--xrd="$definition" "$composition" "$example") | ||
|
|
||
| if [ -n "$observed" ]; then | ||
| render_args+=(--observed-resources="$observed") | ||
| fi | ||
|
|
||
| echo "=== Validating ${example} (api=${api_dir}) ===" | ||
| configuration_from_upbound "$api_dir" | ||
|
|
||
| render_with_retry "${render_args[@]}" --quiet >/dev/null | ||
|
|
||
| "$crossplane_bin" beta validate "$example" "$api_dir" | ||
|
|
||
| render_with_retry \ | ||
| "${render_args[@]}" \ | ||
| --include-full-xr \ | ||
| --quiet \ | ||
| | "$crossplane_bin" beta validate "$api_dir" --error-on-missing-schemas - | ||
|
|
||
| echo "" | ||
| done < <(make --no-print-directory print-examples) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: hops-ops/aws-crossplane-stack
Length of output: 212
🏁 Script executed:
Repository: hops-ops/aws-crossplane-stack
Length of output: 116
🏁 Script executed:
Repository: hops-ops/aws-crossplane-stack
Length of output: 116
🏁 Script executed:
Repository: hops-ops/aws-crossplane-stack
Length of output: 116
🏁 Script executed:
Repository: hops-ops/aws-crossplane-stack
Length of output: 3931
🌐 Web query:
GitHub actions/checkout persist-credentials default value💡 Result:
The default value for the persist-credentials input in the GitHub actions/checkout action is true [1][2][3]. When this option is enabled, the action configures the authentication token or SSH key with the local git configuration, allowing your workflow scripts to run authenticated git commands [1][4][3]. The action automatically removes these credentials during post-job cleanup [1][4]. To opt out of this behavior, you can explicitly set persist-credentials to false in your workflow file [1][5].
Citations:
🌐 Web query:
GitHub actions/checkout persist-credentials default value💡 Result:
The default value of the GitHub Actions checkout step input persist-credentials is true.[1][2] In the actions/checkout action.yml, persist-credentials is defined with default: true.[2] The README also documents that the token/credentials are persisted locally unless you set persist-credentials: false to opt out.[1][3].
Citations:
🌐 Web query:
GitHub actions/checkout persist-credentials default value💡 Result:
For GitHub Actions actions/checkout, the input persist-credentials default value is true. [1][2][3] This means that if you don’t set persist-credentials explicitly, the checkout action will configure the token/SSH key in the local git config (enabling authenticated git commands), and the token is removed during post-job cleanup. [2][4][1]
Citations:
Pin GitHub Actions to commit SHAs and disable persisted checkout credentials
.github/workflows/on-pr.yamluses mutable action refs (actions/checkout@v6,actions/cache@v5,docker/login-action@v3.7.0,upbound/action-up-project@v1.1.2); pin each to an exact commit SHA (applies to checkout: 35, cache: 38, docker login: 64, build: 71).persist-credentialsat its default (true), so the workflow token is configured in git; setpersist-credentials: falseto reduce token exposure since later steps execute code from the checked-out repo.crossplane/crossplane@masterviacurl ... | sh; pin the script to a commit SHA (or use a release artifact) to avoid executing an unpinned source.Suggested hardening
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 34-35: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 35-35: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 Prompt for AI Agents
Source: Linters/SAST tools