{"id":50886054,"url":"https://github.com/hops-ops/workflows-crossplane","last_synced_at":"2026-06-15T17:02:22.529Z","repository":{"id":356589664,"uuid":"1223931744","full_name":"hops-ops/workflows-crossplane","owner":"hops-ops","description":"Mirror of unbounded-tech/workflows-crossplane with hops-ops-specific evolution on feature branches","archived":false,"fork":false,"pushed_at":"2026-05-08T18:10:32.000Z","size":109,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-08T20:26:40.672Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hops-ops.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-28T19:50:13.000Z","updated_at":"2026-05-08T18:10:17.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/hops-ops/workflows-crossplane","commit_stats":null,"previous_names":["hops-ops/workflows-crossplane"],"tags_count":56,"template":false,"template_full_name":null,"purl":"pkg:github/hops-ops/workflows-crossplane","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Fworkflows-crossplane","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Fworkflows-crossplane/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Fworkflows-crossplane/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Fworkflows-crossplane/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hops-ops","download_url":"https://codeload.github.com/hops-ops/workflows-crossplane/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hops-ops%2Fworkflows-crossplane/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34372130,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-15T17:02:21.669Z","updated_at":"2026-06-15T17:02:22.523Z","avatar_url":"https://github.com/hops-ops.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Crossplane GitHub Workflows\n\nThis repository contains shared GitHub Actions workflows for Crossplane projects, focusing on quality validation and CI/CD automation.\n\n## Workflows\n\n### Setup (`setup.yaml`)\n\nA reusable workflow that performs the common setup and build steps shared by all other workflows. Running this workflow first populates the cache, allowing dependent workflows to skip redundant setup work.\n\n#### Purpose\n\nWhen running multiple workflows (validate, test, e2e, publish) in parallel, each would independently perform the same setup steps: checkout, install tools, authenticate, and build. This duplicates work up to 10x depending on how many workflows run concurrently.\n\nBy calling `setup` first and making other workflows depend on it via `needs`, the cache is populated once and shared across all subsequent jobs. This significantly reduces total CI time and resource usage.\n\n#### Inputs\n\n- `crossplane_version` (optional): Crossplane CLI version to install (default: `v2.0.2`)\n- `ghcr_user` (optional): GitHub Container Registry username for pulling images\n\n#### Secrets\n\n- `GH_PAT` (optional): Personal access token for GitHub Container Registry access (required if `ghcr_user` is provided)\n\n#### Permissions\n\nRequires the following permissions in the calling workflow:\n- `packages: read` (for GHCR access)\n- `contents: read` (for checking out code)\n\n#### What It Does\n\n1. Checks out the repository\n2. Restores/creates cache for Upbound and Crossplane CLI\n3. Installs and configures the Upbound CLI\n4. Installs Crossplane CLI\n5. Authenticates with GitHub Container Registry\n6. Builds the project using `up` (populating the cache for dependent workflows)\n\n#### Usage\n\nCall `setup` first, then have other workflows depend on it:\n\n```yaml\nname: CI\n\non:\n  pull_request:\n    branches: [main]\n  push:\n    branches: [main]\n\npermissions:\n  contents: read\n  packages: read\n\njobs:\n  setup:\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/setup.yaml@main\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n\n  validate:\n    needs: setup\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/validate.yaml@main\n    with:\n      examples: '[{\"example\": \"examples/claim.yaml\"}]'\n      api_path: 'apis/myapi'\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n\n  test:\n    needs: setup\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/test.yaml@main\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n\n  e2e:\n    needs: setup\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/e2e.yaml@main\n    with:\n      aws: true\n      aws-use-oidc: true\n      aws-account-id: \"123456789012\"\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n```\n\nIn this example, `setup` runs first and populates the cache. Then `validate`, `test`, and `e2e` run in parallel, each benefiting from the pre-warmed cache instead of duplicating the build step.\n\n### Validate (`validate.yaml`)\n\nA reusable workflow that validates Crossplane compositions and examples using the Upbound CLI and Crossplane beta validate command.\n\n#### Inputs\n\n- `composition` (optional): Composition YAML filename (default: `composition.yaml`)\n- `examples` (required): Examples input. Accepts either a single example string or a JSON array. JSON arrays can be of strings (legacy) or objects (new format with `observed_resources` and/or `api_path`):\n  - Single example: `\"examples/claim.yaml\"`\n  - Array of strings: `[\"examples/claim.yaml\", \"examples/another.yaml\"]`\n  - Array of objects (single API): `[{\"example\": \"examples/claim.yaml\", \"observed_resources\": \"examples/observed-resources/step-1/\"}]`\n  - Array of objects (multi-API): `[{\"example\": \"examples/foo/minimal.yaml\", \"api_path\": \"apis/foos\"}, {\"example\": \"examples/bar/minimal.yaml\", \"api_path\": \"apis/bars\"}]`\n- `api_path` (optional): Path to your API directory containing your XRD definitions. Used as fallback when an example does not specify its own `api_path`. Required if no examples specify `api_path`.\n- `crossplane_version` (optional): Crossplane CLI version to install (default: `v2.0.2`)\n- `error_on_missing_schemas` (optional): Whether to error on missing schemas during validation (default: `true`)\n- `ghcr_user` (optional): GitHub Container Registry username for pushing images\n\n#### Secrets\n\n- `GH_PAT` (optional): Personal access token for GitHub Container Registry write access (required if `ghcr_user` is provided)\n\n#### Permissions\n\nRequires the following permissions in the calling workflow:\n- `packages: write` (for GHCR access)\n- `contents: write` (for checking out code)\n- `issues: write` (for potential issue reporting)\n- `pull-requests: write` (for pull request comments)\n\n#### What It Does\n\n1. Caches Upbound and Crossplane CLI installations\n2. Authenticates with Upbound (without logging into registry)\n3. Installs Crossplane CLI\n4. Logs into GitHub Container Registry (if `ghcr_user` provided)\n5. Builds the project using `up` (Upbound CLI)\n6. Renders the composition example\n7. Validates the example against XRD schemas\n8. Performs additional validation on the rendered composition\n\n#### Usage\n\nTo use this workflow in your Crossplane composition repository:\n\n```yaml\nname: Validate\n\non:\n  pull_request:\n    branches: [ main ]\n\njobs:\n  validate:\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/validate.yaml@main\n    with:\n      examples: '[{\"example\": \"examples/claim.yaml\"}]'\n      api_path: 'package'\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n```\n\n##### Multi-API repos\n\nFor repositories that contain multiple XRDs in separate `apis/\u003cname\u003e/` subdirectories, specify `api_path` per example instead of (or in addition to) the top-level input:\n\n```yaml\njobs:\n  validate:\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/validate.yaml@main\n    with:\n      examples: |\n        [\n          { \"example\": \"examples/foos/minimal.yaml\", \"api_path\": \"apis/foos\" },\n          { \"example\": \"examples/bars/minimal.yaml\", \"api_path\": \"apis/bars\" }\n        ]\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n```\n\nEach matrix run resolves `api_path` per example: the per-example value takes precedence, otherwise the top-level `inputs.api_path` is used. The validation fails fast if neither is set for a given example.\n\n#### Prerequisites\n\n- Your repository should contain Crossplane composition and XRD definitions\n- Enable GitHub Container Registry access if pushing packages\n- Ensure your examples are valid YAML and reference correct schemas\n\n### Test (`test.yaml`)\n\nA reusable workflow that runs Crossplane tests using the Upbound CLI testing framework.\n\n#### Inputs\n\n- `crossplane_version` (optional): Crossplane CLI version to install (default: `v2.0.2`)\n- `ghcr_user` (optional): GitHub Container Registry username for pulling/pushing images\n\n#### Secrets\n\n- `GH_PAT` (optional): Personal access token for GitHub Container Registry write access (required if `ghcr_user` is provided)\n\n#### Permissions\n\nRequires the following permissions in the calling workflow:\n- `packages: write` (for GHCR access)\n- `contents: write` (for checking out code)\n- `issues: write` (for potential issue reporting)\n- `pull-requests: write` (for pull request comments)\n\n#### What It Does\n\n1. Caches Upbound and Crossplane CLI installations\n2. Authenticates with Upbound (without logging into registry)\n3. Installs Crossplane CLI\n4. Logs into GitHub Container Registry (if `ghcr_user` provided)\n5. Builds the project using `up` (Upbound CLI)\n6. Runs all tests located in the `tests/` directory using `up test run`\n\n#### Usage\n\n```yaml\nname: Test\n\non:\n  push:\n    branches: [ main ]\n\njobs:\n  test:\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/test.yaml@main\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n```\n\n### E2E (`e2e.yaml`)\n\nA reusable workflow that runs end-to-end tests for Crossplane compositions using Kind clusters and real cloud providers.\n\n#### Inputs\n\n- `crossplane_version` (optional): Crossplane CLI version to install (default: `v2.0.2`)\n- `ghcr_user` (optional): GitHub Container Registry username for pulling/pushing images\n- `pattern` (optional): Test file pattern (default: `tests/e2e*`)\n- `timeout-minutes` (optional): Timeout in minutes for the e2e test step (default: `20`)\n- `cleanup-timeout-minutes` (optional): Timeout in minutes for the cleanup step (default: `10`)\n- `github` (optional): Enable GitHub credentials setup for `provider-upjet-github` (default: `false`)\n- `github-auth-mode` (optional): GitHub auth mode for `provider-upjet-github` credentials: `auto`, `app`, or `token` (default: `auto`)\n- `gh-app-id` (optional): GitHub App ID used when `github-auth-mode` is `app`; install it on the target owner with repository `Administration: write`\n- `gh-owner` (optional): GitHub owner (org or user) for `provider-upjet-github` credentials\n- `aws` (optional): Enable AWS credentials setup (default: `false`)\n- `aws-use-oidc` (optional): Use GitHub OIDC to assume an AWS role (default: `false`)\n- `aws-role-name` (optional): AWS IAM role name to assume via OIDC (default: `hops-github-actions`)\n- `aws-role-arn` (optional): AWS IAM role ARN to assume via OIDC (overrides `aws-role-name` + `aws-account-id`)\n- `aws-account-id` (optional): AWS account ID used to build role ARN when `aws-role-arn` is not provided (quote values with leading zeros)\n- `aws-region` (optional): AWS region for OIDC credential configuration (default: `us-east-1`)\n- `debug-resource-types` (optional): JSON array of resource types to debug and delete on test failure. These resources will be logged for debugging and deleted during cleanup to handle sibling resources not removed by cascade deletion (e.g., `[\"network.hops.ops.com.ai\"]`)\n- `debug-get-yaml` (optional): Show `kubectl get -o yaml` output for failed resources (default: `false`)\n- `debug-describe` (optional): Show `kubectl describe` output for failed resources (default: `true`)\n- `debug-usages` (optional): Show `kubectl get usages` output for debugging (default: `true`)\n- `namespace` (optional): Kubernetes namespace for test resources (default: `default`)\n\n#### Secrets\n\n- `GH_PAT` (optional): Personal access token for GitHub Container Registry write access (required if `ghcr_user` is provided)\n- `GH_PROVIDER_TOKEN` (optional): GitHub token or PAT for `provider-upjet-github` E2E tests when `github-auth-mode` is `token`; it needs repo admin access on the target owner (fine-grained: `Administration: write`, org-level resources may need `admin:org`)\n- `GH_APP_KEY` (optional): GitHub App private key for `provider-upjet-github` E2E tests when `github-auth-mode` is `app`; the app installation should have repository `Administration: write` on the target owner\n- `AWS_ACCESS_KEY_ID` (optional): AWS Access Key ID for E2E tests (required if `aws` is `true` and `aws-use-oidc` is `false`)\n- `AWS_SECRET_ACCESS_KEY` (optional): AWS Secret Access Key for E2E tests (required if `aws` is `true` and `aws-use-oidc` is `false`)\n- `AWS_SESSION_TOKEN` (optional): AWS Session Token for E2E tests (required for OIDC/assumed roles when providing credentials via secrets)\n\n#### Permissions\n\nRequires the following permissions in the calling workflow:\n- `packages: read` (for GHCR access)\n- `contents: read` (for checking out code)\n- `id-token: write` (for OIDC authentication with AWS, if using assumable roles)\n\n#### What It Does\n\n1. Caches Upbound and Crossplane CLI installations\n2. Authenticates with Upbound (without logging into registry)\n3. Installs Crossplane CLI\n4. Logs into GitHub Container Registry\n5. Builds the project using `up` (Upbound CLI)\n6. Creates GitHub credentials files for `provider-upjet-github` using either app auth or a token (if `github: true`)\n7. Creates AWS credentials file (if `aws: true`)\n8. Runs e2e tests using `up test run` with `--e2e` flag\n9. On test failure: logs debug info and deletes root resource type plus all `debug-resource-types`\n10. Waits for managed resources to be cleaned up\n\n#### Usage\n\nBasic usage without AWS:\n\n```yaml\nname: E2E Tests\n\non:\n  push:\n    branches: [ main ]\n\njobs:\n  e2e:\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/e2e.yaml@main\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n```\n\nWith `provider-upjet-github` credentials using a token:\n\n```yaml\njobs:\n  e2e:\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/e2e.yaml@main\n    with:\n      github: true\n      github-auth-mode: token\n      gh-owner: hops-ops\n    secrets:\n      GH_PROVIDER_TOKEN: ${{ secrets.GH_PROVIDER_TOKEN }}\n```\n\nWith `provider-upjet-github` credentials using a GitHub App:\n\n```yaml\njobs:\n  e2e:\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/e2e.yaml@main\n    with:\n      github: true\n      github-auth-mode: app\n      gh-app-id: ${{ vars.GH_APP_ID }}\n      gh-owner: hops-ops\n    secrets:\n      GH_APP_KEY: ${{ secrets.GH_APP_KEY }}\n```\n\nWith AWS credentials using OIDC role assumption (recommended):\n\n```yaml\nname: E2E Tests\n\non:\n  push:\n    branches: [ main ]\n\npermissions:\n  id-token: write\n  contents: read\n  packages: read\n\njobs:\n  e2e:\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/e2e.yaml@main\n    with:\n      aws: true\n      aws-use-oidc: true\n      aws-account-id: \"123456789012\"\n      aws-role-name: hops-github-actions\n      aws-region: us-east-1\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n```\n\nWith AWS credentials using OIDC assumable role via a separate job:\n\n```yaml\nname: E2E Tests\n\non:\n  push:\n    branches: [ main ]\n\npermissions:\n  id-token: write\n  contents: read\n  packages: read\n\njobs:\n  aws-credentials:\n    runs-on: ubuntu-latest\n    outputs:\n      aws_access_key_id: ${{ steps.creds.outputs.aws-access-key-id }}\n      aws_secret_access_key: ${{ steps.creds.outputs.aws-secret-access-key }}\n      aws_session_token: ${{ steps.creds.outputs.aws-session-token }}\n    steps:\n      - name: Configure AWS Credentials\n        id: creds\n        uses: aws-actions/configure-aws-credentials@v4\n        with:\n          role-to-assume: arn:aws:iam::123456789012:role/github-actions-role\n          aws-region: us-east-1\n          output-credentials: true\n\n  e2e:\n    needs: aws-credentials\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/e2e.yaml@main\n    with:\n      aws: true\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n      AWS_ACCESS_KEY_ID: ${{ needs.aws-credentials.outputs.aws_access_key_id }}\n      AWS_SECRET_ACCESS_KEY: ${{ needs.aws-credentials.outputs.aws_secret_access_key }}\n      AWS_SESSION_TOKEN: ${{ needs.aws-credentials.outputs.aws_session_token }}\n```\n\nWith static AWS credentials (if OIDC is not available):\n\n```yaml\nname: E2E Tests\n\non:\n  push:\n    branches: [ main ]\n\njobs:\n  e2e:\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/e2e.yaml@main\n    with:\n      aws: true\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}\n      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n```\n\n#### Migrating from `e2e-aws.yaml`\n\nThe `e2e-aws.yaml` workflow is deprecated. To migrate to `e2e.yaml`, add `aws: true` to your inputs:\n\n**Before:**\n```yaml\njobs:\n  e2e:\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/e2e-aws.yaml@main\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}\n      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n```\n\n**After:**\n```yaml\njobs:\n  e2e:\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/e2e.yaml@main\n    with:\n      aws: true\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}\n      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}\n```\n\n### E2E AWS (`e2e-aws.yaml`) - Deprecated\n\n\u003e **Deprecated:** Use `e2e.yaml` with `aws: true` instead. See migration guide above.\n\nThis workflow is maintained for backwards compatibility only and will be removed in a future release.\n\n### Publish (`publish.yaml`)\n\nA reusable workflow that publishes Crossplane packages to a registry using the Upbound CLI.\n\n#### Inputs\n\n- `tag` (required): Tag to use when publishing the package\n- `crossplane_version` (optional): Crossplane CLI version to install (default: `v2.0.2`)\n- `ghcr_user` (optional): GitHub Container Registry username for pushing packages\n\n#### Secrets\n\n- `GH_PAT` (optional): Personal access token for GitHub Container Registry write access (required if `ghcr_user` is provided)\n\n#### Permissions\n\nRequires the following permissions in the calling workflow:\n- `packages: write` (for GHCR access)\n- `contents: write` (for checking out code)\n- `issues: write` (for potential issue reporting)\n- `pull-requests: write` (for pull request comments)\n\n#### What It Does\n\n1. Caches Upbound and Crossplane CLI installations\n2. Authenticates with Upbound (without logging into registry)\n3. Installs Crossplane CLI\n4. Logs into GitHub Container Registry (if `ghcr_user` provided)\n5. Builds the project using `up` (Upbound CLI)\n6. Publishes the built package to the configured registry with the specified tag\n\n#### Usage\n\n```yaml\nname: Publish\n\non:\n  release:\n    types: [ published ]\n\njobs:\n  publish:\n    uses: unbounded-tech/workflows-crossplane/.github/workflows/publish.yaml@main\n    with:\n      tag: ${{ github.event.release.tag_name }}\n    secrets:\n      GH_PAT: ${{ secrets.GH_PAT }}\n```\n\n## Dependencies Management\n\nThis repository uses [Renovate](https://renovatebot.com/) for automated dependency updates on GitHub Actions versions and other dependencies. The configuration extends the recommended settings from the Renovate configuration preset.\n\n## Contributing\n\nContributions to improve these workflows are welcome. Please ensure that new workflows follow GitHub Actions best practices and include comprehensive documentation.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhops-ops%2Fworkflows-crossplane","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhops-ops%2Fworkflows-crossplane","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhops-ops%2Fworkflows-crossplane/lists"}