├── .DS_Store ├── .gitignore ├── README.md ├── code-analysis ├── .DS_Store ├── README.md ├── delivery │ ├── delivery.yml │ └── source │ │ └── gitops-source-template.yml ├── supply-chain │ ├── build │ │ └── kpack │ │ │ ├── cluster-builder.yml │ │ │ ├── cluster-stack.yml │ │ │ ├── cluster-store.yml │ │ │ └── image-template.yml │ ├── code-analysis │ │ └── sonar │ │ │ ├── run-template.yml │ │ │ ├── source-template.yml │ │ │ └── task.yml │ ├── config │ │ └── config-template.yml │ ├── deliverable │ │ └── template.yml │ ├── source │ │ └── git-source-template.yml │ ├── supply-chain.yml │ └── writer │ │ └── git │ │ ├── run-template.yml │ │ ├── secret.yml │ │ └── source-template.yml └── workload.yml ├── github-pr ├── README.md └── supply-chain │ ├── config-writer │ ├── run-template.yml │ └── source-template.yml │ ├── pull-request │ ├── run-template.yml │ ├── task.yml │ └── template.yml │ └── source-test-scan-to-url.yml ├── image-prebuilt ├── .DS_Store ├── README.md ├── delivery │ ├── delivery.yml │ └── source │ │ └── image │ │ └── source-template.yml ├── supply-chain │ ├── config │ │ └── config-template.yml │ ├── deliverable │ │ └── template.yml │ ├── scan │ │ └── image │ │ │ ├── image-template.yml │ │ │ ├── scan-policy.yml │ │ │ └── scan-template.yml │ ├── source │ │ └── image-repo-template.yml │ ├── supply-chain.yml │ └── writer │ │ ├── run-template.yml │ │ ├── task.yml │ │ └── template.yml └── workload-imageprebuilt.yml ├── multi-cluster ├── README.md ├── deliverable-to-run-cluster-reconciler.yml ├── rbac │ ├── deliverable-cluster-role-binding.yml │ └── deliverable-cluster-role.yml └── supply-chain │ ├── deliverable-config-writer │ └── cluster-template.yml │ ├── deliverable-config │ └── config-template.yml │ └── source-to-url.yml ├── multi-language-support-with-sonar ├── README.md ├── clusterdelivery │ ├── deliverable-config-writer │ │ ├── commit-and-pr-task.yaml │ │ ├── commit-and-pr-taskrun-runtemplate.yaml │ │ └── config-writer-and-pull-requester-template.yaml │ ├── deliverable-config │ │ └── config-template.yml │ └── delivery.yml └── supplychain │ ├── deliverable-config-writer │ └── cluster-template.yml │ ├── deliverable-config │ └── config-template.yml │ ├── source-analyzer │ ├── run-template.yml │ ├── source-template.yml │ ├── task-dotnet.yml │ └── task.yml │ ├── source-test-analyze-scan-to-url.yml │ └── source-tester │ ├── run-template.yml │ └── source-template.yml └── shared ├── .DS_Store ├── delivery └── deploy │ └── deployment.yml ├── git-secret.yml ├── registry-secret.yml ├── secret.yml ├── service-account.yml └── supply-chain └── deploy └── k8s └── app-deploy.yml /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x95castle1/custom-cartographer-supply-chain-examples/6f0778ce94efc310684215e82308c34d8cb2e127/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | values.yml -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # custom-cartographer-supply-chain-examples 2 | 3 | ## Prerequisites 4 | 5 | 1. Kubernetes v1.19+ 6 | 7 | ```bash 8 | kind create cluster --image kindest/node:v1.21.1 9 | ``` 10 | 11 | 2. [Carvel] tools for templating and groups of Kubernetes objects to the api 12 | server 13 | 14 | - [ytt]: templating the credentials 15 | - [kapp]: submitting objects to Kubernetes 16 | 17 | 3. Cartographer, and dependencies used in the example 18 | 19 | To install `cartographer`, refer to [README.md](../../README.md). 20 | 21 | All that `cartographer` does is choreograph the passing of results from a 22 | Kubernetes object to another, following the graph described in the 23 | [ClusterSupplyChain] object. 24 | 25 | This means that `cartographer` by itself is not very useful - its powers arise 26 | from integrating other Kubernetes resources that when tied together with a 27 | supplychain, forms something powerful. 28 | 29 | Install the following utilities as well as Cartographer! 30 | 31 | - [kpack](https://github.com/pivotal/kpack/blob/main/docs/install.md), 32 | for providing an opinionated way of continuously building container 33 | images using buildpacks 34 | 35 | 36 | - [kapp-controller](https://carvel.dev/kapp-controller/docs/latest/install/), 37 | for providing us with the ability of deploying multiple 38 | Kubernetes objects as a single unit 39 | 40 | 4. A container image registry in which you have authorization to push images. The 41 | credentials will be passed to kpack in the configuration steps below. 42 | 43 | 5. [Tree](https://github.com/ahmetb/kubectl-tree), a tool that we will use to observe the objects created. 44 | 45 | 6. Install [tekton] 46 | 47 | ```bash 48 | export TEKTON_VERSION=0.30.0 49 | kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/previous/v$TEKTON_VERSION/release.yaml 50 | ``` 51 | 52 | 7. Additional setup instructions to run the examples here are in the readme doc per usecase subfolder. 53 | 54 | -------------------------------------------------------------------------------- /code-analysis/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x95castle1/custom-cartographer-supply-chain-examples/6f0778ce94efc310684215e82308c34d8cb2e127/code-analysis/.DS_Store -------------------------------------------------------------------------------- /code-analysis/README.md: -------------------------------------------------------------------------------- 1 | ## Run the code-analysis use case 2 | 3 | > For non-java workloads looking to use sonar for code quality analysis, consider using the [tekton sonarqube scanner task](https://hub.tekton.dev/tekton/task/sonarqube-scanner). This [repo](https://gitlab.com/drawsmcgraw/cartographer-sonar) is an example custom supply chain to take advantage of this reusable task. 4 | 5 | ## Prerequisites 6 | 7 | 1. Install flux [source-controller](https://fluxcd.io/docs/gitops-toolkit/source-watcher/#install-flux) for providing the ability to find new commits to a git 8 | repository and making it internally available to other resources. 9 | 10 | 2. Install the [git-cli task](https://github.com/tektoncd/catalog/tree/main/task/git-cli/0.2) from the 11 | [tekton catalog](https://github.com/tektoncd/catalog). This is used to write to the git repo. 12 | 13 | ```bash 14 | kapp deploy --yes -a tekton-git-cli -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/git-cli/0.2/git-cli.yaml 15 | ``` 16 | 17 | 3. Install [sonarqube](https://docs.sonarqube.org/latest/setup/sonarqube-on-kubernetes/) (skip if you already have a sonarqube instance running in a cluster) 18 | 19 | ## Run 20 | 21 | > assumes current working directory is `repo-root/code-analysis` 22 | 23 | Submit a workload to run through a supply chain with the following steps: 24 | 25 | **get source** → **run test and sonar code quality analysis** → **build image** → **deploy** → **write config** → **stamp out a deliverable** and 26 | 27 | Deploy the deliverable produced from the supply chain through cluster delivery with the following steps: 28 | 29 | **get source from the 'write config' (last step) in the supply chain** → **deploy** 30 | ``` 31 | kapp deploy --yes -a code-analysis-demo -c \ 32 | -f <(ytt --ignore-unknown-comments -f . -f ../values.yml) \ 33 | -f <(ytt --ignore-unknown-comments -f ../shared -f ../values.yml) 34 | ``` 35 | -------------------------------------------------------------------------------- /code-analysis/delivery/delivery.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterDelivery 3 | metadata: 4 | name: deliver 5 | spec: 6 | selector: 7 | workload-type: deliver 8 | workload-intent: code-analysis 9 | resources: 10 | - name: source-provider 11 | templateRef: 12 | kind: ClusterSourceTemplate 13 | name: gitops-source 14 | 15 | - name: deployer 16 | templateRef: 17 | kind: ClusterDeploymentTemplate 18 | name: app-deploy 19 | # in a supply chain, the output of a source template is only available as a `source` 20 | # in a delivery, a source template's output can be consumed as a `deployment` 21 | # every ClusterDeploymentTemplate must be passed exactly one deployment. the deployment 22 | # is not named (as other inputs can be) 23 | deployment: 24 | resource: source-provider -------------------------------------------------------------------------------- /code-analysis/delivery/source/gitops-source-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterSourceTemplate 3 | metadata: 4 | name: gitops-source 5 | spec: 6 | urlPath: .status.artifact.url 7 | revisionPath: .status.artifact.revision 8 | 9 | template: 10 | apiVersion: source.toolkit.fluxcd.io/v1beta1 11 | kind: GitRepository 12 | metadata: 13 | name: $(deliverable.metadata.name)$-app 14 | spec: 15 | interval: 1m0s 16 | url: $(deliverable.spec.source.git.url)$ 17 | ref: $(deliverable.spec.source.git.ref)$ 18 | secretRef: 19 | name: gitops-ssh-secret -------------------------------------------------------------------------------- /code-analysis/supply-chain/build/kpack/cluster-builder.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | --- 3 | apiVersion: kpack.io/v1alpha2 4 | kind: ClusterBuilder 5 | metadata: 6 | name: java-builder 7 | spec: 8 | serviceAccountRef: 9 | name: #@ data.values.service_account_name 10 | namespace: default 11 | tag: #@ data.values.image_prefix + "java-builder" 12 | stack: 13 | name: stack 14 | kind: ClusterStack 15 | store: 16 | name: java-store 17 | kind: ClusterStore 18 | order: 19 | - group: 20 | - id: paketo-buildpacks/java -------------------------------------------------------------------------------- /code-analysis/supply-chain/build/kpack/cluster-stack.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kpack.io/v1alpha2 3 | kind: ClusterStack 4 | metadata: 5 | name: stack 6 | spec: 7 | id: "io.buildpacks.stacks.bionic" 8 | buildImage: 9 | image: "paketobuildpacks/build:base-cnb" 10 | runImage: 11 | image: "paketobuildpacks/run:base-cnb" -------------------------------------------------------------------------------- /code-analysis/supply-chain/build/kpack/cluster-store.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: kpack.io/v1alpha2 3 | kind: ClusterStore 4 | metadata: 5 | name: java-store 6 | spec: 7 | sources: 8 | - image: gcr.io/paketo-buildpacks/java -------------------------------------------------------------------------------- /code-analysis/supply-chain/build/kpack/image-template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: carto.run/v1alpha1 3 | kind: ClusterImageTemplate 4 | metadata: 5 | name: image 6 | spec: 7 | params: 8 | - name: image_prefix 9 | default: some-default-prefix- 10 | 11 | imagePath: .status.latestImage 12 | 13 | template: 14 | apiVersion: kpack.io/v1alpha2 15 | kind: Image 16 | metadata: 17 | name: $(workload.metadata.name)$ 18 | spec: 19 | tag: $(params.image_prefix)$$(workload.metadata.name)$ 20 | serviceAccountName: $(workload.spec.serviceAccountName)$ 21 | builder: 22 | kind: ClusterBuilder 23 | name: java-builder 24 | source: 25 | blob: 26 | url: $(sources.tested-source.url)$ 27 | build: 28 | env: $(workload.spec.build.env)$ -------------------------------------------------------------------------------- /code-analysis/supply-chain/code-analysis/sonar/run-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterRunTemplate 3 | metadata: 4 | name: tekton-sonar-taskrun 5 | spec: 6 | outputs: 7 | url: spec.params[?(@.name=="source-url")].value 8 | revision: spec.params[?(@.name=="source-revision")].value 9 | template: 10 | apiVersion: tekton.dev/v1beta1 11 | kind: TaskRun 12 | metadata: 13 | generateName: $(runnable.metadata.name)$- 14 | labels: $(runnable.metadata.labels)$ 15 | spec: 16 | params: 17 | - name: source-url 18 | value: $(runnable.spec.inputs.source-url)$ 19 | - name: source-revision 20 | value: $(runnable.spec.inputs.source-revision)$ 21 | taskRef: {name: $(selected.metadata.name)$} -------------------------------------------------------------------------------- /code-analysis/supply-chain/code-analysis/sonar/source-template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: carto.run/v1alpha1 3 | kind: ClusterSourceTemplate 4 | metadata: 5 | name: tested-source 6 | spec: 7 | urlPath: .status.outputs.url 8 | revisionPath: .status.outputs.revision 9 | 10 | template: 11 | apiVersion: carto.run/v1alpha1 12 | kind: Runnable 13 | metadata: 14 | name: $(workload.metadata.name)$ 15 | spec: 16 | serviceAccountName: $(workload.spec.serviceAccountName)$ 17 | runTemplateRef: 18 | name: tekton-sonar-taskrun 19 | 20 | selector: 21 | resource: 22 | apiVersion: tekton.dev/v1beta1 23 | kind: Task 24 | matchingLabels: 25 | task: code-analysis 26 | 27 | inputs: 28 | source-url: $(sources.source.url)$ 29 | source-revision: $(sources.source.revision)$ 30 | -------------------------------------------------------------------------------- /code-analysis/supply-chain/code-analysis/sonar/task.yml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | labels: 5 | task: code-analysis 6 | name: sonar 7 | namespace: default 8 | spec: 9 | params: 10 | - name: source-url 11 | - name: source-revision 12 | steps: 13 | - image: harbor-repo.vmware.com/dockerhub-proxy-cache/library/gradle 14 | name: code-analysis 15 | resources: {} 16 | script: |- 17 | cd `mktemp -d` 18 | 19 | wget -qO- $(params.source-url) | tar xvz 20 | chmod +x mvnw 21 | ./mvnw verify sonar:sonar -------------------------------------------------------------------------------- /code-analysis/supply-chain/config/config-template.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | --- 3 | apiVersion: carto.run/v1alpha1 4 | kind: ClusterConfigTemplate 5 | metadata: 6 | name: app-config 7 | spec: 8 | configPath: .data.manifest 9 | 10 | ytt: | 11 | #@ load("@ytt:data", "data") 12 | apiVersion: v1 13 | kind: ConfigMap 14 | metadata: 15 | name: #@ data.values.workload.metadata.name 16 | data: 17 | #@yaml/text-templated-strings 18 | manifest: | 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | name: (@= data.values.workload.metadata.name @)-app 23 | spec: 24 | serviceAccountName: (@= data.values.workload.spec.serviceAccountName @) 25 | selector: 26 | matchLabels: 27 | app: (@= data.values.workload.metadata.name @) 28 | template: 29 | metadata: 30 | labels: 31 | app: (@= data.values.workload.metadata.name @) 32 | spec: 33 | containers: 34 | - name: main 35 | image: (@= data.values.image @) -------------------------------------------------------------------------------- /code-analysis/supply-chain/deliverable/template.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | 3 | apiVersion: carto.run/v1alpha1 4 | kind: ClusterTemplate 5 | metadata: 6 | name: deliverable-template 7 | spec: 8 | params: 9 | - name: gitops_server 10 | default: "" 11 | - name: gitops_repository 12 | default: "" 13 | - name: gitops_branch 14 | default: "main" 15 | 16 | ytt: | 17 | #@ load("@ytt:data", "data") 18 | 19 | #@ def giturl(): 20 | #@ return "ssh://git@" + "/".join([ 21 | #@ data.values.params.gitops_server, 22 | #@ data.values.params.gitops_repository 23 | #@ ]) 24 | #@ end 25 | 26 | apiVersion: carto.run/v1alpha1 27 | kind: Deliverable 28 | metadata: 29 | name: #@ data.values.workload.metadata.name 30 | labels: 31 | workload-type: deliver 32 | workload-intent: code-analysis 33 | spec: 34 | serviceAccountName: #@ data.values.workload.spec.serviceAccountName 35 | source: 36 | git: 37 | url: #@ giturl() 38 | ref: 39 | branch: #@ data.values.params.gitops_branch 40 | commit: #@ data.values.source.revision -------------------------------------------------------------------------------- /code-analysis/supply-chain/source/git-source-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterSourceTemplate 3 | metadata: 4 | name: source 5 | spec: 6 | urlPath: .status.artifact.url 7 | revisionPath: .status.artifact.revision 8 | 9 | template: 10 | apiVersion: source.toolkit.fluxcd.io/v1beta1 11 | kind: GitRepository 12 | metadata: 13 | name: $(workload.metadata.name)$ 14 | spec: 15 | interval: 1m0s 16 | url: $(workload.spec.source.git.url)$ 17 | ref: $(workload.spec.source.git.ref)$ 18 | secretRef: 19 | name: gitops-ssh-secret -------------------------------------------------------------------------------- /code-analysis/supply-chain/supply-chain.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 VMware 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | --- 15 | #@ load("@ytt:data", "data") 16 | --- 17 | apiVersion: carto.run/v1alpha1 18 | kind: ClusterSupplyChain 19 | metadata: 20 | name: code-analysis-supply-chain 21 | spec: 22 | selector: 23 | workload-intent: code-analysis 24 | resources: 25 | - name: source-provider 26 | templateRef: 27 | kind: ClusterSourceTemplate 28 | name: source 29 | 30 | - name: source-tester-analyzer 31 | templateRef: 32 | kind: ClusterSourceTemplate 33 | name: tested-source 34 | sources: 35 | - resource: source-provider 36 | name: source 37 | 38 | - name: image-builder 39 | templateRef: 40 | kind: ClusterImageTemplate 41 | name: image 42 | params: 43 | - name: image_prefix 44 | value: #@ data.values.image_prefix 45 | sources: 46 | - resource: source-tester-analyzer 47 | name: tested-source 48 | 49 | - name: deployer 50 | templateRef: 51 | kind: ClusterTemplate 52 | name: app-deploy 53 | images: 54 | - resource: image-builder 55 | name: image 56 | 57 | - name: config-provider 58 | templateRef: 59 | kind: ClusterConfigTemplate 60 | name: app-config 61 | images: 62 | - resource: image-builder 63 | name: image 64 | 65 | - name: git-writer 66 | templateRef: 67 | kind: ClusterSourceTemplate 68 | name: git-writer-source # returns the commit sha of what was pushed to git 69 | configs: 70 | - resource: config-provider 71 | name: app-config 72 | 73 | - name: deliverable 74 | templateRef: 75 | kind: ClusterTemplate 76 | name: deliverable-template 77 | sources: 78 | - resource: git-writer 79 | name: git-writer-source # commit sha of what git-writter wrote is included in the deliverable -------------------------------------------------------------------------------- /code-analysis/supply-chain/writer/git/run-template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: carto.run/v1alpha1 3 | kind: ClusterRunTemplate 4 | metadata: 5 | name: git-writer 6 | spec: 7 | outputs: 8 | revision: '.status.taskResults[?(@.name=="commit")].value' 9 | template: 10 | apiVersion: tekton.dev/v1beta1 11 | kind: TaskRun 12 | metadata: 13 | generateName: $(runnable.metadata.name)$- 14 | spec: 15 | taskRef: 16 | name: git-cli 17 | workspaces: 18 | - name: source 19 | emptyDir: { } 20 | - name: input 21 | emptyDir: { } 22 | - name: ssh-directory 23 | secret: 24 | secretName: git-ssh-secret 25 | params: 26 | - name: GIT_USER_NAME 27 | value: $(runnable.spec.inputs.git_username)$ 28 | - name: GIT_USER_EMAIL 29 | value: $(runnable.spec.inputs.git_user_email)$ 30 | - name: USER_HOME 31 | value: /root 32 | - name: GIT_SCRIPT 33 | value: | 34 | export COMMIT_MESSAGE="$(runnable.spec.inputs.commit_message)$" 35 | export BRANCH="$(runnable.spec.inputs.branch)$" 36 | if [[ -n "$(runnable.spec.inputs.skip_host_checking)$" && "$(runnable.spec.inputs.skip_host_checking)$" = true ]] 37 | then 38 | export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" 39 | fi 40 | if [[ -n "$(runnable.spec.inputs.git_ssh_variant)$" ]] 41 | then 42 | export GIT_SSH_VARIANT="$(runnable.spec.inputs.git_ssh_variant)$" 43 | fi 44 | git init 45 | if [[ -n "$(runnable.spec.inputs.git_server_port)$" ]]; then 46 | git remote add origin $(runnable.spec.inputs.git_ssh_user)$@$(runnable.spec.inputs.git_server)$:$(runnable.spec.inputs.git_server_port)$/$(runnable.spec.inputs.git_repository)$ 47 | else 48 | git remote add origin $(runnable.spec.inputs.git_ssh_user)$@$(runnable.spec.inputs.git_server)$:$(runnable.spec.inputs.git_repository)$ 49 | fi 50 | # TODO remove the fetch and branch 51 | git fetch 52 | git branch 53 | git pull origin "`git remote show origin | grep "HEAD branch" | sed 's/.*: //'`" 54 | git pull origin "$BRANCH" || git branch "$BRANCH" 55 | git checkout "$BRANCH" 56 | export CONFIG_MAP_FIELD=$(runnable.spec.inputs.input_config_map_field)$ 57 | export DATA="$(runnable.spec.inputs.data)$" 58 | echo "$DATA" | tee "$CONFIG_MAP_FIELD" 59 | git add . 60 | git commit --allow-empty -m "$COMMIT_MESSAGE" 61 | git push --set-upstream origin "$BRANCH" -------------------------------------------------------------------------------- /code-analysis/supply-chain/writer/git/secret.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | 3 | --- 4 | apiVersion: v1 5 | kind: Secret 6 | metadata: 7 | name: git-ssh-secret 8 | data: 9 | id_rsa: #@ data.values.git_writer.base64_encoded_ssh_key 10 | known_hosts: #@ data.values.git_writer.base64_encoded_known_hosts -------------------------------------------------------------------------------- /code-analysis/supply-chain/writer/git/source-template.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | 3 | apiVersion: carto.run/v1alpha1 4 | kind: ClusterSourceTemplate 5 | metadata: 6 | name: git-writer-source 7 | spec: 8 | urlPath: .status.outputs.revision # this is unused, yet needs to be valued to be deemed a valid ClusterSourceTemplate output 9 | revisionPath: .status.outputs.revision 10 | params: 11 | - name: git_writer_username 12 | default: #@ data.values.git_writer.username 13 | - name: git_writer_user_email 14 | default: #@ data.values.git_writer.user_email 15 | - name: git_writer_commit_message 16 | default: #@ data.values.git_writer.message 17 | - name: git_writer_ssh_user 18 | default: #@ data.values.git_writer.ssh_user 19 | - name: git_writer_server 20 | default: #@ data.values.git_writer.server 21 | - name: git_writer_port 22 | default: #@ data.values.git_writer.port 23 | - name: git_writer_repository 24 | default: #@ data.values.git_writer.repository 25 | - name: git_writer_branch 26 | default: #@ data.values.git_writer.branch 27 | - name: git_writer_skip_host_checking 28 | default: false 29 | - name: git_writer_ssh_variant 30 | default: ssh 31 | template: 32 | apiVersion: carto.run/v1alpha1 33 | kind: Runnable 34 | metadata: 35 | name: $(workload.metadata.name)$-git-writer 36 | spec: 37 | serviceAccountName: $(workload.spec.serviceAccountName)$ 38 | runTemplateRef: 39 | name: git-writer 40 | 41 | inputs: 42 | input_config_map_name: $(workload.metadata.name)$ 43 | input_config_map_field: manifest.yaml 44 | 45 | git_username: $(params.git_writer_username)$ 46 | git_user_email: $(params.git_writer_user_email)$ 47 | commit_message: $(params.git_writer_commit_message)$ 48 | git_ssh_user: $(params.git_writer_ssh_user)$ 49 | git_server: $(params.git_writer_server)$ 50 | git_server_port: $(params.git_writer_port)$ 51 | git_repository: $(params.git_writer_repository)$ 52 | branch: $(params.git_writer_branch)$ 53 | skip_host_checking: $(params.git_writer_skip_host_checking)$ 54 | git_ssh_variant: $(params.git_writer_ssh_variant)$ 55 | data: $(config)$ -------------------------------------------------------------------------------- /code-analysis/workload.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | --- 3 | apiVersion: carto.run/v1alpha1 4 | kind: Workload 5 | metadata: 6 | name: code-analysis 7 | namespace: default 8 | labels: 9 | app.kubernetes.io/part-of: code-analysis 10 | workload-intent: code-analysis 11 | spec: 12 | serviceAccountName: #@ data.values.service_account_name 13 | params: 14 | - name: gitops_server 15 | value: github.com 16 | - name: gitops_repository 17 | value: Mpluya/code-analysis-config 18 | - name: gitops_branch 19 | value: main 20 | source: 21 | git: 22 | ref: 23 | branch: main 24 | url: ssh://git@github.com/Mpluya/code-analysis 25 | -------------------------------------------------------------------------------- /github-pr/README.md: -------------------------------------------------------------------------------- 1 | ## Run the github pull request use case 2 | 3 | This is an enhancement on top of the out of the box supply chain templates provided with TAP such that the config produced from a supply chain gets put in a pull request. Adding a pull request in the workflow provides an opportunity for a review before 'change' is realized in a target environment. This is especially important in highly regulated organizations where change management is enforced where every change affecting production has to be reviewed. 4 | 5 | ## Assumption 6 | TAP is installed including any of the out of the box supply chains. 7 | 8 | ## Installation 9 | 1. Follow the instructions for making [Live modification of supply chains and templates](https://docs.vmware.com/en/Tanzu-Application-Platform/1.1/tap/GUID-scc-authoring-supply-chains.html#live-modification-of-supply-chains-and-templates-6). 10 | 11 | Below are the actual steps taken: 12 | - pause reconciliation of tap meta package 13 | ``` 14 | kubectl patch packageinstall/tap -n tap-install -p '{"spec":{"paused":true}}' --type=merge 15 | ``` 16 | - pause reconciliation of the supply chain applied in your cluster (this example uses testing-scanning) 17 | ``` 18 | kubectl patch packageinstall/ootb-supply-chain-testing-scanning -n tap-install -p '{"spec":{"paused":true}}' --type=merge 19 | ``` 20 | 21 | 2. Add `tekton-taskrun` (ClusterRunTemplate used by config-writer) to the template exclusion list in tap values. 22 | ``` 23 | ootb_templates: 24 | excluded_templates: 25 | - 'tekton-taskrun' 26 | ``` 27 | 28 | Update tap - `tanzu package installed update tap -p tap.tanzu.vmware.com -v $TAP_VERSION --values-file tap-values.yml -n tap-install` 29 | 30 | 31 | > assumes current working directory is `repo-root/github-pr` 32 | 33 | 3. Apply the templates (`kubectl apply -f .`) under supply-chain/config-writer and supply-chain/pull-request. If you prefer to use kapp run `kapp deploy -a custom-templates -f .` 34 | 35 | 4. Update the ClusterSupplyChain. This example uses the testing scanning implementation. 36 | ``` 37 | kubectl replace -f source-test-scan-to-url.yml --replace 38 | ``` 39 | 40 | If you're using either basic or testing supply chain, you can still pick up the enhancements from the full sample (source-test-scan-to-url.yml) provided in this repo and apply the following: 41 | - replace the config-writer with the content between comments `# updated config writer template` and `# end updated config writer template`. 42 | 43 | > Note: the sources section will need to be adjusted, for basic - source-provider, for testing - source-tester. 44 | 45 | - add github-pull-request template section 46 | 47 | Cluster supply chain snippet : 48 | ``` 49 | - name: config-writer 50 | templateRef: 51 | kind: ClusterSourceTemplate 52 | name: config-writer-source-template 53 | configs: 54 | - resource: app-config 55 | name: config 56 | sources: 57 | - resource: [source-provider | source-tester] 58 | name: source 59 | params: 60 | - name: serviceAccount 61 | value: default 62 | - name: registry 63 | value: 64 | repository: [ootb supply chain registry repository provided in tap values] 65 | server: [ootb supply chain registry server provided in tap values] 66 | 67 | - name: github-pull-request 68 | templateRef: 69 | kind: ClusterTemplate 70 | name: pull-request 71 | sources: 72 | - resource: config-writer 73 | name: config-writer-source-template 74 | ``` -------------------------------------------------------------------------------- /github-pr/supply-chain/config-writer/run-template.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | 3 | #@ if/end "tekton-taskrun" not in data.values.excluded_templates: 4 | --- 5 | apiVersion: carto.run/v1alpha1 6 | kind: ClusterRunTemplate 7 | metadata: 8 | name: tekton-taskrun 9 | spec: 10 | outputs: 11 | url: spec.params[?(@.name=="git_repository")].value 12 | revision: spec.params[?(@.name=="git_branch")].value 13 | template: 14 | apiVersion: tekton.dev/v1beta1 15 | kind: TaskRun 16 | metadata: 17 | generateName: $(runnable.metadata.name)$- 18 | labels: $(runnable.metadata.labels)$ 19 | spec: 20 | serviceAccountName: $(runnable.spec.inputs.serviceAccount)$ 21 | taskRef: $(runnable.spec.inputs.taskRef)$ 22 | params: $(runnable.spec.inputs.params)$ 23 | -------------------------------------------------------------------------------- /github-pr/supply-chain/config-writer/source-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterSourceTemplate 3 | metadata: 4 | name: config-writer-source-template 5 | spec: 6 | urlPath: .status.outputs.url 7 | revisionPath: .status.outputs.revision 8 | params: 9 | - default: default 10 | name: serviceAccount 11 | - default: {} 12 | name: registry 13 | ytt: | 14 | #@ load("@ytt:data", "data") 15 | #@ load("@ytt:json", "json") 16 | #@ load("@ytt:base64", "base64") 17 | 18 | #@ def has_git_params(): 19 | #@ if 'gitops_repository_prefix' in data.values.params: 20 | #@ return True 21 | #@ end 22 | #@ 23 | #@ if 'gitops_repository' in data.values.params: 24 | #@ return True 25 | #@ end 26 | #@ 27 | #@ return False 28 | #@ end 29 | 30 | #@ def is_gitops(): 31 | #@ return has_git_params() 32 | #@ end 33 | 34 | #@ def param(key): 35 | #@ if not key in data.values.params: 36 | #@ return None 37 | #@ end 38 | #@ return data.values.params[key] 39 | #@ end 40 | 41 | #@ def git_repository(): 42 | #@ if 'gitops_repository' in data.values.params: 43 | #@ return param("gitops_repository") 44 | #@ end 45 | #@ 46 | #@ prefix = param("gitops_repository_prefix") 47 | #@ return prefix + data.values.workload.metadata.name + ".git" 48 | #@ end 49 | 50 | #@ def git_revision(): 51 | #@ return (data.values.source.revision.split("/")[1])[0:7] 52 | #@ end 53 | 54 | #@ def image(): 55 | #@ return "/".join([ 56 | #@ data.values.params.registry.server, 57 | #@ data.values.params.registry.repository, 58 | #@ "-".join([ 59 | #@ data.values.workload.metadata.name, 60 | #@ data.values.workload.metadata.namespace, 61 | #@ "bundle", 62 | #@ ]) 63 | #@ ]) + ":" + data.values.workload.metadata.uid 64 | #@ end 65 | 66 | 67 | --- 68 | apiVersion: carto.run/v1alpha1 69 | kind: Runnable 70 | metadata: 71 | name: #@ data.values.workload.metadata.name + "-config-writer" 72 | labels: 73 | app.kubernetes.io/component: config-writer 74 | #@ if/end hasattr(data.values.workload.metadata, "labels") and hasattr(data.values.workload.metadata.labels, "app.kubernetes.io/part-of"): 75 | app.kubernetes.io/part-of: #@ data.values.workload.metadata.labels["app.kubernetes.io/part-of"] 76 | spec: 77 | #@ if/end hasattr(data.values.workload.spec, "serviceAccountName"): 78 | serviceAccountName: #@ data.values.workload.spec.serviceAccountName 79 | 80 | runTemplateRef: 81 | name: tekton-taskrun 82 | 83 | inputs: 84 | serviceAccount: #@ data.values.params.serviceAccount 85 | taskRef: 86 | kind: ClusterTask 87 | name: #@ "git-writer" if is_gitops() else "image-writer" 88 | params: 89 | #@ if is_gitops(): 90 | - name: git_repository 91 | value: #@ git_repository() 92 | - name: git_branch 93 | value: #@ git_revision() 94 | - name: git_user_name 95 | value: #@ param("gitops_user_name") 96 | - name: git_user_email 97 | value: #@ param("gitops_user_email") 98 | - name: git_commit_message 99 | value: #@ param("gitops_commit_message") 100 | - name: git_files 101 | value: #@ base64.encode(json.encode(data.values.config)) 102 | #@ else: 103 | - name: files 104 | value: #@ base64.encode(json.encode(data.values.config)) 105 | - name: bundle 106 | value: #@ image() 107 | #@ end -------------------------------------------------------------------------------- /github-pr/supply-chain/pull-request/run-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterRunTemplate 3 | metadata: 4 | name: github-open-pr-taskrun 5 | spec: 6 | template: 7 | apiVersion: tekton.dev/v1beta1 8 | kind: TaskRun 9 | metadata: 10 | generateName: $(runnable.metadata.name)$- 11 | labels: 12 | $(runnable.metadata.labels)$ 13 | spec: 14 | serviceAccountName: $(runnable.spec.inputs.serviceAccount)$ 15 | taskRef: {name: $(selected.metadata.name)$} 16 | params: 17 | - name: REPO_FULL_NAME 18 | value: $(runnable.spec.inputs.repo)$ 19 | - name: HEAD 20 | value: $(runnable.spec.inputs.fromBranch)$ 21 | - name: BASE 22 | value: $(runnable.spec.inputs.toBranch)$ 23 | - name: TITLE 24 | value: $(runnable.spec.inputs.title)$ 25 | - name: BODY 26 | value: $(runnable.spec.inputs.body)$ -------------------------------------------------------------------------------- /github-pr/supply-chain/pull-request/task.yml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | name: github-open-pr-task 5 | labels: 6 | task: open-github-pr 7 | annotations: 8 | tekton.dev/categories: Git 9 | tekton.dev/pipelines.minVersion: "0.12.1" 10 | tekton.dev/tags: github 11 | tekton.dev/displayName: "open github pull request" 12 | tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le" 13 | spec: 14 | description: >- 15 | This task will open a PR on Github based on several parameters. 16 | This could be useful in GitOps repositories for example. 17 | 18 | params: 19 | - name: GITHUB_HOST_URL 20 | description: | 21 | The GitHub host, adjust this if you run a GitHub enteprise. 22 | default: "api.github.com" 23 | type: string 24 | 25 | - name: API_PATH_PREFIX 26 | description: | 27 | The API path prefix, GitHub Enterprise has a prefix e.g. /api/v3 28 | default: "" 29 | type: string 30 | 31 | - name: REPO_FULL_NAME 32 | description: | 33 | The GitHub repository full name, e.g.: tektoncd/catalog 34 | type: string 35 | 36 | - name: GITHUB_TOKEN_SECRET_NAME 37 | description: | 38 | The name of the kubernetes secret that contains the GitHub token, default: github 39 | type: string 40 | default: github 41 | 42 | - name: GITHUB_TOKEN_SECRET_KEY 43 | description: | 44 | The key within the kubernetes secret that contains the GitHub token, default: token 45 | type: string 46 | default: token 47 | 48 | - name: AUTH_TYPE 49 | description: | 50 | The type of authentication to use. You could use the less secure "Basic" for example 51 | type: string 52 | default: Bearer 53 | 54 | - name: HEAD 55 | description: | 56 | The name of the branch where your changes are implemented. 57 | type: string 58 | 59 | - name: BASE 60 | description: | 61 | The name of the branch you want the changes pulled into. 62 | type: string 63 | 64 | - name: BODY 65 | description: | 66 | The body description of the pull request. 67 | type: string 68 | 69 | - name: TITLE 70 | description: | 71 | The title of the pull request. 72 | type: string 73 | 74 | results: 75 | - name: NUMBER 76 | description: Number of the created pull request. 77 | 78 | - name: URL 79 | description: URL of the created pull request. 80 | 81 | volumes: 82 | - name: githubtoken 83 | secret: 84 | secretName: $(params.GITHUB_TOKEN_SECRET_NAME) 85 | 86 | steps: 87 | - name: open-pr 88 | volumeMounts: 89 | - name: githubtoken 90 | readOnly: true 91 | mountPath: /etc/github-open-pr 92 | env: 93 | - name: PULLREQUEST_NUMBER_PATH 94 | value: $(results.NUMBER.path) 95 | - name: PULLREQUEST_URL_PATH 96 | value: $(results.URL.path) 97 | 98 | image: registry.access.redhat.com/ubi8/python-38:1-34.1599745032 99 | script: | 100 | #!/usr/libexec/platform-python 101 | 102 | """This script will open a PR on Github""" 103 | 104 | import json 105 | import os 106 | import sys 107 | import http.client 108 | 109 | github_token = open("/etc/github-open-pr/$(params.GITHUB_TOKEN_SECRET_KEY)", "r").read() 110 | 111 | open_pr_url = "$(params.API_PATH_PREFIX)" + "/repos/$(params.REPO_FULL_NAME)/pulls" 112 | 113 | data = { 114 | "head": "$(params.HEAD)", 115 | "base": "$(params.BASE)", 116 | "title": "$(params.TITLE)", 117 | "body": """$(params.BODY)""" 118 | } 119 | print("Sending this data to GitHub: ") 120 | print(data) 121 | 122 | authHeader = "$(params.AUTH_TYPE) " + github_token 123 | 124 | # This is for our fake github server 125 | if "$(params.GITHUB_HOST_URL)".startswith("http://"): 126 | conn = http.client.HTTPConnection("$(params.GITHUB_HOST_URL)" 127 | .replace("http://", "")) 128 | else: 129 | conn = http.client.HTTPSConnection("$(params.GITHUB_HOST_URL)") 130 | 131 | conn.request( 132 | "POST", 133 | open_pr_url, 134 | body=json.dumps(data), 135 | headers={ 136 | "User-Agent": "TektonCD, the peaceful cat", 137 | "Authorization": authHeader, 138 | "Accept": "application/vnd.github.v3+json ", 139 | }) 140 | resp = conn.getresponse() 141 | if not str(resp.status).startswith("2"): 142 | print("Error: %d" % (resp.status)) 143 | print(resp.read()) 144 | sys.exit(1) 145 | else: 146 | # https://docs.github.com/en/rest/reference/pulls#create-a-pull-request 147 | body = json.loads(resp.read().decode()) 148 | 149 | open(os.environ.get('PULLREQUEST_NUMBER_PATH'), 'w').write(f'{body["number"]}') 150 | open(os.environ.get('PULLREQUEST_URL_PATH'), 'w').write(body["html_url"]) 151 | 152 | print("GitHub pull request created for $(params.REPO_FULL_NAME): " 153 | f'number={body["number"]} url={body["html_url"]}') -------------------------------------------------------------------------------- /github-pr/supply-chain/pull-request/template.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | --- 3 | apiVersion: carto.run/v1alpha1 4 | kind: ClusterTemplate 5 | metadata: 6 | name: pull-request 7 | spec: 8 | params: 9 | - name: pr_title 10 | default: "Supply chain produced a deliverable" 11 | - name: pr_body 12 | default: "Please review the updated artifacts." 13 | - name: serviceAccount 14 | default: default 15 | 16 | ytt: | 17 | #@ load("@ytt:data", "data") 18 | 19 | #@ def repo_host(): 20 | #@ source_url = data.values.source.url 21 | #@ if source_url.startswith("ssh"): 22 | #@ return (source_url.split("ssh://git@github.com/")[1]).split(".git")[0] 23 | #@ end 24 | #@ 25 | #@ return (source_url.split("https://git@github.com/")[1]).split(".git")[0] 26 | #@ end 27 | 28 | --- 29 | apiVersion: carto.run/v1alpha1 30 | kind: Runnable 31 | metadata: 32 | name: #@ data.values.workload.metadata.name + "-pull-request" 33 | labels: 34 | tekton.dev/task: github-open-pr 35 | app.kubernetes.io/component: pull-request 36 | #@ if/end hasattr(data.values.workload.metadata, "labels") and hasattr(data.values.workload.metadata.labels, "app.kubernetes.io/part-of"): 37 | app.kubernetes.io/part-of: #@ data.values.workload.metadata.labels["app.kubernetes.io/part-of"] 38 | spec: 39 | #@ if/end hasattr(data.values.workload.spec, "serviceAccountName"): 40 | serviceAccountName: #@ data.values.workload.spec.serviceAccountName 41 | 42 | runTemplateRef: 43 | name: github-open-pr-taskrun 44 | 45 | selector: 46 | resource: 47 | apiVersion: tekton.dev/v1beta1 48 | kind: Task 49 | matchingLabels: 50 | task: open-github-pr 51 | 52 | inputs: 53 | serviceAccount: #@ data.values.params.serviceAccount 54 | repo: #@ repo_host() 55 | fromBranch: #@ data.values.source.revision 56 | toBranch: #@ data.values.params["gitops_branch"] 57 | title: #@ data.values.params.pr_title 58 | body: #@ data.values.params.pr_body -------------------------------------------------------------------------------- /github-pr/supply-chain/source-test-scan-to-url.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterSupplyChain 3 | metadata: 4 | name: source-test-scan-to-url 5 | spec: 6 | params: 7 | - default: main 8 | name: gitops_branch 9 | - default: supplychain 10 | name: gitops_user_name 11 | - default: supplychain 12 | name: gitops_user_email 13 | - default: supplychain@cluster.local 14 | name: gitops_commit_message 15 | - default: gitops-ssh 16 | name: gitops_ssh_secret 17 | resources: 18 | - name: source-provider 19 | params: 20 | - name: serviceAccount 21 | value: default 22 | - name: gitImplementation 23 | value: go-git 24 | templateRef: 25 | kind: ClusterSourceTemplate 26 | name: source-template 27 | - name: deliverable 28 | params: 29 | - name: registry 30 | value: 31 | repository: tapsme 32 | server: index.docker.io 33 | templateRef: 34 | kind: ClusterTemplate 35 | name: deliverable-template 36 | - name: source-tester 37 | sources: 38 | - name: source 39 | resource: source-provider 40 | templateRef: 41 | kind: ClusterSourceTemplate 42 | name: testing-pipeline 43 | - name: source-scanner 44 | sources: 45 | - name: source 46 | resource: source-tester 47 | templateRef: 48 | kind: ClusterSourceTemplate 49 | name: source-scanner-template 50 | - name: image-builder 51 | params: 52 | - name: serviceAccount 53 | value: default 54 | - name: clusterBuilder 55 | value: default 56 | - name: registry 57 | value: 58 | repository: tapsme 59 | server: index.docker.io 60 | sources: 61 | - name: source 62 | resource: source-scanner 63 | templateRef: 64 | kind: ClusterImageTemplate 65 | name: kpack-template 66 | - images: 67 | - name: image 68 | resource: image-builder 69 | name: image-scanner 70 | templateRef: 71 | kind: ClusterImageTemplate 72 | name: image-scanner-template 73 | - images: 74 | - name: image 75 | resource: image-scanner 76 | name: config-provider 77 | params: 78 | - name: serviceAccount 79 | value: default 80 | templateRef: 81 | kind: ClusterConfigTemplate 82 | name: convention-template 83 | - configs: 84 | - name: config 85 | resource: config-provider 86 | name: app-config 87 | templateRef: 88 | kind: ClusterConfigTemplate 89 | name: config-template 90 | 91 | # updated config writer template 92 | - name: config-writer 93 | templateRef: 94 | kind: ClusterSourceTemplate 95 | name: config-writer-source-template 96 | configs: 97 | - resource: app-config 98 | name: config 99 | sources: 100 | - resource: source-scanner 101 | name: source-scanner-template 102 | params: 103 | - name: serviceAccount 104 | value: default 105 | - name: registry 106 | value: 107 | repository: tapsme 108 | server: index.docker.io 109 | # end updated config writer template 110 | 111 | - name: github-pull-request 112 | templateRef: 113 | kind: ClusterTemplate 114 | name: pull-request 115 | sources: 116 | - resource: config-writer 117 | name: config-writer-source-template 118 | 119 | selector: 120 | apps.tanzu.vmware.com/has-tests: "true" 121 | apps.tanzu.vmware.com/workload-type: web -------------------------------------------------------------------------------- /image-prebuilt/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x95castle1/custom-cartographer-supply-chain-examples/6f0778ce94efc310684215e82308c34d8cb2e127/image-prebuilt/.DS_Store -------------------------------------------------------------------------------- /image-prebuilt/README.md: -------------------------------------------------------------------------------- 1 | ## Run the image-prebuilt use case 2 | 3 | This example can be run alongside an existing TAP installation that has the out of the box supply chain - testing and scanning. 4 | If you wish to run this on a cluster that doesnt have TAP, the steps in the prerequisites section are required. 5 | Either approaches (with or without pre-existing TAP install) have been validated and should work. 6 | 7 | ## Prerequisites 8 | 1. Add Tanzu TAP repository 9 | 10 | ```bash 11 | export INSTALL_REGISTRY_USERNAME='[tanzu net username]' 12 | export INSTALL_REGISTRY_PASSWORD='[tanzu net password]' 13 | export INSTALL_REGISTRY_HOSTNAME=registry.tanzu.vmware.com 14 | export TAP_VERSION=[version] 15 | 16 | tanzu secret registry add tap-registry \ 17 | --username ${INSTALL_REGISTRY_USERNAME} --password ${INSTALL_REGISTRY_PASSWORD} \ 18 | --server ${INSTALL_REGISTRY_HOSTNAME} \ 19 | --export-to-all-namespaces --yes 20 | 21 | tanzu package repository add tanzu-tap-repository \ 22 | --url registry.tanzu.vmware.com/tanzu-application-platform/tap-packages:$TAP_VERSION 23 | ``` 24 | 25 | 2. Install Tanzu Source Controller 26 | ```bash 27 | tanzu package install source-controller -p controller.source.apps.tanzu.vmware.com -v [x.x.x] 28 | ``` 29 | 30 | 3. Install Supply Chain Security Tools - Scan 31 | ```bash 32 | tanzu package install scan-controller --package-name scanning.apps.tanzu.vmware.com --version [x.x.x] 33 | ``` 34 | 35 | 4. Install Supply Chain Security Tools - Store 36 | ```bash 37 | tanzu package install metadata-store --package-name metadata-store.apps.tanzu.vmware.com --version [x.x.x] 38 | ``` 39 | 40 | 41 | ## Run 42 | > assumes current working directory is `repo-root/image-prebuilt`: 43 | ``` 44 | kapp deploy --yes -a image-prebuilt-demo -c \ 45 | -f <(ytt --ignore-unknown-comments -f . -f ../values.yml) \ 46 | -f <(ytt --ignore-unknown-comments -f ../shared -f ../values.yml) 47 | ``` 48 | 49 | ## View scan results 50 | Follow the instructions [here](https://docs.vmware.com/en/Tanzu-Application-Platform/1.0/tap/GUID-scst-store-additional.html) -------------------------------------------------------------------------------- /image-prebuilt/delivery/delivery.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterDelivery 3 | metadata: 4 | name: delivery-image-prebuilt 5 | spec: 6 | selector: 7 | deliverable-intent: image-prebuilt 8 | resources: 9 | - name: image-provider 10 | templateRef: 11 | kind: ClusterSourceTemplate 12 | name: deliverable-image-source 13 | 14 | - name: deployer 15 | templateRef: 16 | kind: ClusterDeploymentTemplate 17 | name: app-deploy-tpl 18 | # in a supply chain, the output of a source template is only available as a `source` 19 | # in a delivery, a source template's output can be consumed as a `deployment` 20 | # every ClusterDeploymentTemplate must be passed exactly one deployment. the deployment 21 | # is not named (as other inputs can be) 22 | deployment: 23 | resource: image-provider -------------------------------------------------------------------------------- /image-prebuilt/delivery/source/image/source-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterSourceTemplate 3 | metadata: 4 | name: deliverable-image-source 5 | spec: 6 | revisionPath: .status.artifact.revision 7 | urlPath: .status.artifact.url 8 | 9 | template: 10 | apiVersion: source.apps.tanzu.vmware.com/v1alpha1 11 | kind: ImageRepository 12 | metadata: 13 | name: $(deliverable.metadata.name)$-app 14 | spec: 15 | serviceAccount: $(deliverable.spec.serviceAccountName)$ 16 | interval: 1m0s 17 | image: $(deliverable.spec.source.image)$ -------------------------------------------------------------------------------- /image-prebuilt/supply-chain/config/config-template.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | --- 3 | apiVersion: carto.run/v1alpha1 4 | kind: ClusterConfigTemplate 5 | metadata: 6 | name: app-config 7 | spec: 8 | configPath: .data 9 | params: 10 | - name: registry_server 11 | default: "" 12 | - name: registry_repository 13 | default: "" 14 | 15 | ytt: | 16 | #@ load("@ytt:data", "data") 17 | #@ load("@ytt:yaml", "yaml") 18 | 19 | #@ def delivery(): 20 | apiVersion: apps/v1 21 | kind: Deployment 22 | metadata: 23 | name: #@ data.values.workload.metadata.name + "-app" 24 | spec: 25 | serviceAccountName: #@ data.values.workload.spec.serviceAccountName 26 | selector: 27 | matchLabels: 28 | app: #@ data.values.workload.metadata.name 29 | template: 30 | metadata: 31 | labels: 32 | app: #@ data.values.workload.metadata.name 33 | spec: 34 | containers: 35 | - name: main 36 | image: #@ data.values.image 37 | #@ end 38 | 39 | apiVersion: v1 40 | kind: ConfigMap 41 | metadata: 42 | name: #@ data.values.workload.metadata.name 43 | data: 44 | delivery.yml: #@ yaml.encode(delivery()) -------------------------------------------------------------------------------- /image-prebuilt/supply-chain/deliverable/template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterTemplate 3 | metadata: 4 | name: deliverable-tpl 5 | spec: 6 | params: 7 | - default: {} 8 | name: registry 9 | ytt: | 10 | #@ load("@ytt:data", "data") 11 | 12 | #@ def image(): 13 | #@ return "/".join([ 14 | #@ data.values.params.registry_server, 15 | #@ data.values.params.registry_repository, 16 | #@ "-".join([ 17 | #@ data.values.workload.metadata.name, 18 | #@ data.values.workload.metadata.namespace, 19 | #@ "bundle", 20 | #@ ]) 21 | #@ ]) + ":" + data.values.workload.metadata.uid 22 | #@ end 23 | 24 | 25 | --- 26 | apiVersion: carto.run/v1alpha1 27 | kind: Deliverable 28 | metadata: 29 | name: #@ data.values.workload.metadata.name 30 | labels: 31 | deliverable-intent: image-prebuilt 32 | #@ if/end hasattr(data.values.workload.metadata, "labels") and hasattr(data.values.workload.metadata.labels, "app.kubernetes.io/part-of"): 33 | app.kubernetes.io/part-of: #@ data.values.workload.metadata.labels["app.kubernetes.io/part-of"] 34 | spec: 35 | #@ if/end hasattr(data.values.workload.spec, "serviceAccountName"): 36 | serviceAccountName: #@ data.values.workload.spec.serviceAccountName 37 | 38 | source: 39 | image: #@ image() -------------------------------------------------------------------------------- /image-prebuilt/supply-chain/scan/image/image-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterImageTemplate 3 | metadata: 4 | name: image 5 | spec: 6 | imagePath: .status.compliantArtifact.registry.image 7 | ytt: | 8 | #@ load("@ytt:data", "data") 9 | apiVersion: scanning.apps.tanzu.vmware.com/v1beta1 10 | kind: ImageScan 11 | metadata: 12 | name: #@ data.values.workload.metadata.name 13 | labels: 14 | app.kubernetes.io/component: image-scan 15 | spec: 16 | registry: 17 | image: #@ data.values.image 18 | scanTemplate: image-scan-template 19 | scanPolicy: sample-scan-policy -------------------------------------------------------------------------------- /image-prebuilt/supply-chain/scan/image/scan-policy.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | items: 3 | - apiVersion: scanning.apps.tanzu.vmware.com/v1beta1 4 | kind: ScanPolicy 5 | metadata: 6 | name: sample-scan-policy 7 | namespace: default 8 | spec: 9 | regoFile: | 10 | package policies 11 | 12 | default isCompliant = false 13 | 14 | # Accepted Values: "Critical", "High", "Medium", "Low", "Negligible", "UnknownSeverity" 15 | violatingSeverities := ["UnknownSeverity"] # ATTENTION: this should include Critical, High, and Medium but temporarily defaulting to just UnknownSeverity for demo purposes 16 | ignoreCVEs := [] 17 | 18 | contains(array, elem) = true { 19 | array[_] = elem 20 | } else = false { true } 21 | 22 | isSafe(match) { 23 | fails := contains(violatingSeverities, match.Ratings.Rating[_].Severity) 24 | not fails 25 | } 26 | 27 | isSafe(match) { 28 | ignore := contains(ignoreCVEs, match.Id) 29 | ignore 30 | } 31 | 32 | isCompliant = isSafe(input.currentVulnerability) 33 | kind: List 34 | metadata: 35 | resourceVersion: "" 36 | selfLink: "" -------------------------------------------------------------------------------- /image-prebuilt/supply-chain/scan/image/scan-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: scanning.apps.tanzu.vmware.com/v1beta1 2 | kind: ScanTemplate 3 | metadata: 4 | name: image-scan-template 5 | namespace: default 6 | spec: 7 | template: 8 | containers: 9 | - args: 10 | - -c 11 | - ./image/copy-docker-config.sh /secret-data && ./image/scan-image.sh /workspace 12 | scan.xml true 13 | command: 14 | - /bin/bash 15 | image: registry.tanzu.vmware.com/tanzu-application-platform/tap-packages@sha256:bdce1113e2c940305fa9fd34d7cae2dce247c3e309fcd442efc769b590aa19e4 16 | imagePullPolicy: IfNotPresent 17 | name: scanner 18 | resources: 19 | limits: 20 | cpu: 1000m 21 | requests: 22 | cpu: 250m 23 | memory: 128Mi 24 | volumeMounts: 25 | - mountPath: /.docker 26 | name: docker 27 | readOnly: false 28 | - mountPath: /workspace 29 | name: workspace 30 | readOnly: false 31 | - mountPath: /secret-data 32 | name: registry-cred 33 | readOnly: true 34 | imagePullSecrets: 35 | - name: tanzu-reg-cred 36 | restartPolicy: Never 37 | securityContext: 38 | runAsNonRoot: true 39 | volumes: 40 | - emptyDir: {} 41 | name: docker 42 | - emptyDir: {} 43 | name: workspace 44 | - name: registry-cred 45 | secret: 46 | secretName: reg-cred -------------------------------------------------------------------------------- /image-prebuilt/supply-chain/source/image-repo-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterImageTemplate 3 | metadata: 4 | name: prebuilt-image 5 | spec: 6 | imagePath: .spec.image 7 | 8 | template: 9 | apiVersion: source.apps.tanzu.vmware.com/v1alpha1 10 | kind: ImageRepository 11 | metadata: 12 | name: $(workload.metadata.name)$ 13 | spec: 14 | serviceAccount: $(workload.spec.serviceAccountName)$ 15 | interval: 1m0s 16 | image: $(workload.spec.source.image)$ -------------------------------------------------------------------------------- /image-prebuilt/supply-chain/supply-chain.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: carto.run/v1alpha1 3 | kind: ClusterSupplyChain 4 | metadata: 5 | name: image-prebuilt-supply-chain 6 | spec: 7 | selector: 8 | workload-intent: image-prebuilt 9 | resources: 10 | - name: image-provider 11 | templateRef: 12 | kind: ClusterImageTemplate 13 | name: prebuilt-image 14 | 15 | - name: image-scanner 16 | templateRef: 17 | kind: ClusterImageTemplate 18 | name: image 19 | images: 20 | - resource: image-provider 21 | name: prebuilt-image 22 | 23 | - name: deployer 24 | templateRef: 25 | kind: ClusterTemplate 26 | name: app-deploy 27 | images: 28 | - resource: image-scanner 29 | name: image 30 | 31 | - name: config-provider 32 | templateRef: 33 | kind: ClusterConfigTemplate 34 | name: app-config 35 | images: 36 | - resource: image-scanner 37 | name: image 38 | 39 | # writes config from app-config to be pushed as a bundle by imgpkg 40 | - name: image-writer 41 | templateRef: 42 | kind: ClusterTemplate 43 | name: image-writer 44 | configs: 45 | - resource: config-provider 46 | name: app-config 47 | 48 | - name: deliverable 49 | templateRef: 50 | kind: ClusterTemplate 51 | name: deliverable-tpl -------------------------------------------------------------------------------- /image-prebuilt/supply-chain/writer/run-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterRunTemplate 3 | metadata: 4 | name: tekton-taskrun-tpl 5 | spec: 6 | template: 7 | apiVersion: tekton.dev/v1beta1 8 | kind: TaskRun 9 | metadata: 10 | generateName: $(runnable.metadata.name)$- 11 | labels: $(runnable.metadata.labels)$ 12 | spec: 13 | params: $(runnable.spec.inputs.params)$ 14 | serviceAccountName: $(runnable.spec.inputs.serviceAccount)$ 15 | taskRef: $(runnable.spec.inputs.taskRef)$ -------------------------------------------------------------------------------- /image-prebuilt/supply-chain/writer/task.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | apiVersion: tekton.dev/v1beta1 4 | kind: ClusterTask 5 | metadata: 6 | name: image-writer-task 7 | spec: 8 | description: |- 9 | a task that writes a given set of files (provided as a json base64-encoded) 10 | to a container image registry as an image making use of the imgpkg bundle 11 | format. 12 | params: 13 | - description: name of the registry + repository to push the bundle to 14 | name: bundle 15 | type: string 16 | - description: | 17 | base64-encoded json map of files to write to registry, for example - eyAiUkVBRE1FLm1kIjogIiMgUmVhZG1lIiB9 18 | name: files 19 | type: string 20 | steps: 21 | - image: registry.tanzu.vmware.com/tanzu-application-platform/tap-packages@sha256:e5e961933dfc7406d708c88b3226d7fe79266a58b75e2de93ca640ccd310f78d 22 | name: main 23 | resources: {} 24 | script: |- 25 | #!/usr/bin/env bash 26 | 27 | set -o errexit 28 | set -o xtrace 29 | 30 | cd `mktemp -d` 31 | 32 | echo -e "$(params.files)" | base64 --decode > files.json 33 | eval "$(cat files.json | jq -r 'to_entries | .[] | @sh "mkdir -p $(dirname \(.key)) && echo \(.value) > \(.key)"')" 34 | 35 | mkdir -p .imgpkg 36 | 37 | echo -e "---\napiVersion: imgpkg.carvel.dev/v1alpha1\nkind: ImagesLock" > ./.imgpkg/images.yml 38 | 39 | export IMGPKG_ENABLE_IAAS_AUTH=false 40 | imgpkg push -b $(params.bundle) -f . 41 | cat ./.imgpkg/images.yml 42 | securityContext: 43 | runAsUser: 0 -------------------------------------------------------------------------------- /image-prebuilt/supply-chain/writer/template.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | 3 | apiVersion: carto.run/v1alpha1 4 | kind: ClusterTemplate 5 | metadata: 6 | name: image-writer 7 | spec: 8 | params: 9 | - name: registry_server 10 | default: "" 11 | - name: registry_repository 12 | default: "" 13 | 14 | ytt: | 15 | #@ load("@ytt:data", "data") 16 | #@ load("@ytt:json", "json") 17 | #@ load("@ytt:base64", "base64") 18 | 19 | #@ def image_bundle(): 20 | #@ return "/".join([ 21 | #@ data.values.params.registry_server, 22 | #@ data.values.params.registry_repository, 23 | #@ "-".join([ 24 | #@ data.values.workload.metadata.name, 25 | #@ data.values.workload.metadata.namespace, 26 | #@ "bundle", 27 | #@ ]) 28 | #@ ]) + ":" + data.values.workload.metadata.uid 29 | #@ end 30 | 31 | --- 32 | apiVersion: carto.run/v1alpha1 33 | kind: Runnable 34 | metadata: 35 | name: #@ data.values.workload.metadata.name + "-config-writer" 36 | spec: 37 | #@ if/end hasattr(data.values.workload.spec, "serviceAccountName"): 38 | serviceAccountName: #@ data.values.workload.spec.serviceAccountName 39 | 40 | runTemplateRef: 41 | name: tekton-taskrun-tpl 42 | 43 | inputs: 44 | serviceAccount: #@ data.values.workload.spec.serviceAccountName 45 | taskRef: 46 | kind: ClusterTask 47 | name: image-writer-task 48 | params: 49 | - name: files 50 | value: #@ base64.encode(json.encode(data.values.config)) 51 | - name: bundle 52 | value: #@ image_bundle() -------------------------------------------------------------------------------- /image-prebuilt/workload-imageprebuilt.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | --- 3 | apiVersion: carto.run/v1alpha1 4 | kind: Workload 5 | metadata: 6 | name: image-prebuilt 7 | namespace: default 8 | labels: 9 | app.kubernetes.io/part-of: image-prebuilt 10 | workload-intent: image-prebuilt 11 | spec: 12 | serviceAccountName: #@ data.values.service_account_name 13 | params: 14 | - name: registry_server 15 | value: harbor-repo.vmware.com 16 | - name: registry_repository 17 | value: tapsme/cartographer 18 | source: 19 | image: harbor-repo.vmware.com/tapsme/special-spring-boot-app:0.0.2 -------------------------------------------------------------------------------- /multi-cluster/README.md: -------------------------------------------------------------------------------- 1 | ## Run the multi-cluster use case 2 | 3 | ## Assumption 4 | Purposeful TAP clusters (multi-cluster) are setup. At a minimum 2 distinct TAP clusters are involved - build (to turn source code into cloud native image) and run (to deploy). 5 | 6 | 7 | ## Rationale 8 | This is an enhancement on top of the out of the box supply chain provided with TAP to realize a cartographer deliverable produced from a TAP build cluster onto a TAP run cluster. It leverages the custom resource App (kappctrl.k14s.io/v1alpha1) to target the appropriate run cluster where deliverables read from git repositories will be applied. 9 | 10 | ## Installation: 11 | **The installation steps are to be run in your TAP cluster where you submit a workload (e.g. build cluster).** 12 | 13 | 1. Follow the instructions for making [Live modification of supply chains and templates](https://docs.vmware.com/en/Tanzu-Application-Platform/1.1/tap/GUID-scc-authoring-supply-chains.html#live-modification-of-supply-chains-and-templates-6). 14 | 15 | Below are the actual steps taken: 16 | - pause reconciliation of tap meta package 17 | ``` 18 | kubectl patch packageinstall/tap -n tap-install -p '{"spec":{"paused":true}}' --type=merge 19 | ``` 20 | - pause reconciliation of the supply chain applied in your cluster (this example uses basic) 21 | ``` 22 | kubectl patch packageinstall/ootb-supply-chain-basic -n tap-install -p '{"spec":{"paused":true}}' --type=merge 23 | ``` 24 | 25 | > assumes current working directory is `repo-root/multi-cluster` 26 | 27 | 3. Apply the templates (`kubectl apply -f .`) under supply-chain/deliverable-config and supply-chain/deliverable-config -writer. If you prefer to use kapp run `kapp deploy -a custom-templates -f .` 28 | 29 | 4. Update the ClusterSupplyChain. This example uses the basic supply cgain. 30 | ``` 31 | kubectl replace -f source-to-url.yml --replace 32 | ``` 33 | 34 | **The step below is OPTIONAL and should be applied in your TAP cluster where you run workload(s) (e.g. run cluster).** 35 | 36 | 5. (Optional) Apply the templates (`kubectl apply -f .`) under supply-chain/rbac in your target run cluster. This leverages the default service account in the default namespace and is given ClusterRole permission to manage deliverables regardless of the namespace. This is done for convenience. You are free to configure your own service account and provide fine grained permissions following least privilege access. 37 | 38 | ## Notes: 39 | 40 | - The secret specified in App.spec.cluster.kubeconfigSecretRef holds kubeconfig info of a target run cluster. This enables 41 | cross-cluster communication. 42 | 43 | Sample kube-config.yml template using a service account from your target run cluster-namespace. 44 | ``` 45 | apiVersion: v1 46 | kind: Config 47 | clusters: 48 | - cluster: 49 | certificate-authority-data: ${ca} 50 | server: ${server} 51 | name: ${clusterName} 52 | contexts: 53 | - context: 54 | cluster: ${clusterName} 55 | user: ${serviceAccount} 56 | name: ${serviceAccount}@${clusterName} 57 | current-context: ${serviceAccount}@${clusterName} 58 | users: 59 | - name: ${serviceAccount} 60 | user: 61 | token: ${token} 62 | ``` 63 | 64 | Sample command to create kubeconfig as a secret. **Note that this secret should be created in your TAP cluster where you submit a workload (e.g. build cluster)**. Expect future enhancements on this. 65 | ``` 66 | kubectl -n default create secret generic kubeconfig-deliverable-reconciler-secret --from-file=value=./kubeconfig.yml 67 | ``` -------------------------------------------------------------------------------- /multi-cluster/deliverable-to-run-cluster-reconciler.yml: -------------------------------------------------------------------------------- 1 | apiVersion: kappctrl.k14s.io/v1alpha1 2 | kind: App 3 | metadata: 4 | name: deliverable-to-run-cluster-reconciler 5 | spec: 6 | fetch: 7 | - git: 8 | url: https://github.com/Mpluya/unicorn-run-qa-deliverable 9 | ref: origin/main 10 | syncPeriod: 1m0s 11 | cluster: 12 | # specifies namespace in destination cluster (optional) 13 | namespace: default 14 | # specifies secret containing kubeconfig (required) 15 | kubeconfigSecretRef: 16 | # specifies secret name within app's namespace (required) 17 | name: kubeconfig-deliverable-reconciler-secret 18 | # specifies key that contains kubeconfig (optional) 19 | key: value 20 | deploy: 21 | - kapp: 22 | rawOptions: ["--dangerous-allow-empty-list-of-resources=true"] 23 | template: 24 | - ytt: {} 25 | - kbld: {} -------------------------------------------------------------------------------- /multi-cluster/rbac/deliverable-cluster-role-binding.yml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRoleBinding 3 | metadata: 4 | name: deliverable-reconciler 5 | roleRef: 6 | apiGroup: rbac.authorization.k8s.io 7 | kind: ClusterRole 8 | name: deliverable-reconciler 9 | subjects: 10 | - kind: ServiceAccount 11 | name: default 12 | namespace: default -------------------------------------------------------------------------------- /multi-cluster/rbac/deliverable-cluster-role.yml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1 2 | kind: ClusterRole 3 | metadata: 4 | name: deliverable-reconciler 5 | rules: 6 | - apiGroups: 7 | - carto.run 8 | resources: 9 | - deliverables 10 | verbs: 11 | - "*" -------------------------------------------------------------------------------- /multi-cluster/supply-chain/deliverable-config-writer/cluster-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterTemplate 3 | metadata: 4 | labels: 5 | name: config-writer-deliverable-template 6 | spec: 7 | params: 8 | - default: default 9 | name: serviceAccount 10 | ytt: | 11 | #@ load("@ytt:data", "data") 12 | #@ load("@ytt:json", "json") 13 | #@ load("@ytt:base64", "base64") 14 | 15 | #@ def param(key): 16 | #@ if not key in data.values.params: 17 | #@ return None 18 | #@ end 19 | #@ return data.values.params[key] 20 | #@ end 21 | 22 | 23 | --- 24 | apiVersion: carto.run/v1alpha1 25 | kind: Runnable 26 | metadata: 27 | name: #@ data.values.workload.metadata.name + "-deliverable-config-writer" 28 | labels: 29 | app.kubernetes.io/component: config-writer 30 | #@ if/end hasattr(data.values.workload.metadata, "labels") and hasattr(data.values.workload.metadata.labels, "app.kubernetes.io/part-of"): 31 | app.kubernetes.io/part-of: #@ data.values.workload.metadata.labels["app.kubernetes.io/part-of"] 32 | spec: 33 | #@ if/end hasattr(data.values.workload.spec, "serviceAccountName"): 34 | serviceAccountName: #@ data.values.workload.spec.serviceAccountName 35 | 36 | runTemplateRef: 37 | name: tekton-taskrun 38 | 39 | inputs: 40 | serviceAccount: #@ data.values.params.serviceAccount 41 | taskRef: 42 | kind: ClusterTask 43 | name: #@ "git-writer" 44 | params: 45 | - name: git_repository 46 | value: #@ param("deliverable_repository") 47 | - name: git_branch 48 | value: #@ param("deliverable_branch") 49 | - name: git_user_name 50 | value: #@ param("gitops_user_name") 51 | - name: git_user_email 52 | value: #@ param("gitops_user_email") 53 | - name: git_commit_message 54 | value: #@ param("gitops_commit_message") 55 | - name: git_files 56 | value: #@ base64.encode(json.encode(data.values.config)) -------------------------------------------------------------------------------- /multi-cluster/supply-chain/deliverable-config/config-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterConfigTemplate 3 | metadata: 4 | name: config-deliverable-template 5 | spec: 6 | configPath: .data 7 | ytt: | 8 | #@ load("@ytt:data", "data") 9 | #@ load("@ytt:yaml", "yaml") 10 | 11 | #@ def has_git_params(): 12 | #@ if 'gitops_repository_prefix' in data.values.params: 13 | #@ return True 14 | #@ end 15 | #@ 16 | #@ if 'gitops_repository' in data.values.params: 17 | #@ return True 18 | #@ end 19 | #@ 20 | #@ return False 21 | #@ end 22 | 23 | #@ def is_gitops(): 24 | #@ return has_git_params() 25 | #@ end 26 | 27 | #@ def param(key): 28 | #@ if not key in data.values.params: 29 | #@ return None 30 | #@ end 31 | #@ return data.values.params[key] 32 | #@ end 33 | 34 | #@ def git_repository(): 35 | #@ if 'gitops_repository' in data.values.params: 36 | #@ return param("gitops_repository") 37 | #@ end 38 | #@ 39 | #@ prefix = param("gitops_repository_prefix") 40 | #@ return prefix + data.values.workload.metadata.name + ".git" 41 | #@ end 42 | 43 | #@ def merge_labels(fixed_values): 44 | #@ labels = {} 45 | #@ if hasattr(data.values.workload.metadata, "labels"): 46 | #@ labels.update(data.values.workload.metadata.labels) 47 | #@ end 48 | #@ labels.update(fixed_values) 49 | #@ return labels 50 | #@ end 51 | 52 | #@ def deliverable(): 53 | apiVersion: carto.run/v1alpha1 54 | kind: Deliverable 55 | metadata: 56 | name: #@ data.values.workload.metadata.name 57 | namespace: #@ data.values.workload.metadata.namespace 58 | labels: #@ merge_labels({ "app.kubernetes.io/component": "deliverable", "app.tanzu.vmware.com/deliverable-type": "web" }) 59 | spec: 60 | #@ if/end hasattr(data.values.workload.spec, "serviceAccountName"): 61 | serviceAccountName: #@ data.values.workload.spec.serviceAccountName 62 | 63 | params: 64 | - name: "gitops_ssh_secret" 65 | value: #@ param("gitops_ssh_secret") 66 | 67 | source: 68 | git: 69 | url: #@ git_repository() 70 | ref: 71 | branch: #@ param("gitops_branch") 72 | 73 | #@ end 74 | 75 | --- 76 | apiVersion: v1 77 | kind: ConfigMap 78 | metadata: 79 | name: #@ data.values.workload.metadata.name + "-deliverable" 80 | labels: #@ merge_labels({ "app.kubernetes.io/component": "config" }) 81 | data: 82 | #@yaml/text-templated-strings 83 | (@= data.values.workload.metadata.name @)-deliverable.yml: #@ yaml.encode(deliverable()) -------------------------------------------------------------------------------- /multi-cluster/supply-chain/source-to-url.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterSupplyChain 3 | metadata: 4 | name: source-to-url 5 | spec: 6 | params: 7 | - name: deliverable_repository 8 | default: ssh://git@github.com/Mpluya/unicorn-run-qa-deliverable.git 9 | - name: deliverable_branch 10 | default: main 11 | - default: main 12 | name: gitops_branch 13 | - default: supplychain 14 | name: gitops_user_name 15 | - default: supplychain 16 | name: gitops_user_email 17 | - default: supplychain@cluster.local 18 | name: gitops_commit_message 19 | - default: "" 20 | name: gitops_ssh_secret 21 | resources: 22 | - name: source-provider 23 | params: 24 | - name: serviceAccount 25 | value: default 26 | - name: gitImplementation 27 | value: go-git 28 | templateRef: 29 | kind: ClusterSourceTemplate 30 | name: source-template 31 | - name: image-builder 32 | params: 33 | - name: serviceAccount 34 | value: default 35 | - name: clusterBuilder 36 | value: default 37 | - name: registry 38 | value: 39 | repository: tapsme 40 | server: index.docker.io 41 | sources: 42 | - name: source 43 | resource: source-provider 44 | templateRef: 45 | kind: ClusterImageTemplate 46 | name: kpack-template 47 | - images: 48 | - name: image 49 | resource: image-builder 50 | name: config-provider 51 | params: 52 | - name: serviceAccount 53 | value: default 54 | templateRef: 55 | kind: ClusterConfigTemplate 56 | name: convention-template 57 | - configs: 58 | - name: config 59 | resource: config-provider 60 | name: app-config 61 | templateRef: 62 | kind: ClusterConfigTemplate 63 | name: config-template 64 | - configs: 65 | - name: config 66 | resource: app-config 67 | name: app-config-writer 68 | params: 69 | - name: serviceAccount 70 | value: default 71 | - name: registry 72 | value: 73 | repository: tapsme 74 | server: index.docker.io 75 | templateRef: 76 | kind: ClusterTemplate 77 | name: config-writer-template 78 | 79 | - configs: 80 | name: deliverable-config 81 | templateRef: 82 | kind: ClusterConfigTemplate 83 | name: config-deliverable-template 84 | 85 | - name: deliverable-config-writer 86 | configs: 87 | - name: config 88 | resource: deliverable-config 89 | params: 90 | - name: serviceAccount 91 | value: default 92 | templateRef: 93 | kind: ClusterTemplate 94 | name: config-writer-deliverable-template 95 | 96 | 97 | selector: 98 | apps.tanzu.vmware.com/workload-type: web -------------------------------------------------------------------------------- /multi-language-support-with-sonar/README.md: -------------------------------------------------------------------------------- 1 | 2 | `kapp deploy -a multi-language-support-with-sonar -f multi-language-support-with-sonar` 3 | -------------------------------------------------------------------------------- /multi-language-support-with-sonar/clusterdelivery/deliverable-config-writer/commit-and-pr-task.yaml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | 3 | --- 4 | apiVersion: tekton.dev/v1beta1 5 | kind: ClusterTask 6 | metadata: 7 | name: commit-and-pr 8 | spec: 9 | description: |- 10 | A task that writes a given set of files (provided as a json base64-encoded) 11 | to a git repository under a specified path. A pull request is then opened 12 | to merge the changes into the specified base branch. 13 | params: 14 | - name: repository_owner 15 | description: The owner of the repository, either an organisation or username 16 | type: string 17 | - name: repository_name 18 | description: The name of the repository 19 | type: string 20 | - name: commit_branch 21 | type: string 22 | description: The name of the branch where desired changes are implemented 23 | - name: git_user_email 24 | description: User email address 25 | type: string 26 | default: "example@example.com" 27 | - name: git_user_name 28 | description: User name 29 | type: string 30 | default: "Example" 31 | - name: git_commit_message 32 | description: Message for the git commit 33 | type: string 34 | default: "New Commit" 35 | - name: git_files 36 | type: string 37 | description: > 38 | Base64-encoded json map of files to write to registry, for example - 39 | eyAiUkVBRE1FLm1kIjogIiMgUmVhZG1lIiB9 40 | - name: git_server_address 41 | type: string 42 | description: The git server location 43 | default: https://github.com 44 | - name: git_server_kind 45 | type: string 46 | description: The git server kind (e.g. github, gitlab, gitea, etc) 47 | default: github 48 | - name: pull_request_title 49 | type: string 50 | description: The title of the pull request 51 | - name: pull_request_body 52 | type: string 53 | description: The message body of the pull request 54 | default: "" 55 | - name: base_branch 56 | type: string 57 | description: The name of the branch the desired changes should be pulled in to 58 | default: main 59 | - name: sub_path 60 | description: Sub directory in which to write 61 | type: string 62 | default: "config" 63 | results: 64 | - name: pr-url 65 | description: The url of the successfully created pull request 66 | workspaces: 67 | - name: ws 68 | mountPath: /workspaces/ws 69 | steps: 70 | - name: git-clone-and-push 71 | image: tapsme/config-writer 72 | securityContext: 73 | runAsUser: 0 74 | workingDir: /root 75 | script: | 76 | #!/usr/bin/env bash 77 | 78 | set -o errexit 79 | 80 | commit_branch="$(params.commit_branch)" 81 | if [ -z "$commit_branch" ]; then 82 | commit_branch=$(date +%s | base64) 83 | fi 84 | 85 | set +o xtrace # Avoid leaking secrets, echo sensitive lines 86 | 87 | echo 'git_prefix=$(cat $(credentials.path)/.git-credentials)' 88 | git_prefix=$(cat $(credentials.path)/.git-credentials) 89 | 90 | echo 'git_repository="$git_prefix/$(params.repository_owner)/$(params.repository_name).git"' 91 | git_repository="$git_prefix/$(params.repository_owner)/$(params.repository_name).git" 92 | 93 | echo 'git clone --depth 1 -b "$commit_branch" "$git_repository" ./repo 2>&1 | sed "s|$git_prefix|REDACTED|g' 94 | git clone --depth 1 -b "$commit_branch" "$git_repository" ./repo 2>&1 | sed "s|$git_prefix|REDACTED|g" 95 | echo 'if [ ${PIPESTATUS[0]} -ne 0 ]; then' 96 | if [ ${PIPESTATUS[0]} -ne 0 ]; then 97 | set -o xtrace 98 | cd ./repo 99 | else 100 | echo 'git clone --depth 1 "$git_repository" ./repo 2>&1 | sed "s|$git_prefix|REDACTED|g"' 101 | git clone --depth 1 "$git_repository" ./repo 2>&1 | sed "s|$git_prefix|REDACTED|g" 102 | set -o xtrace 103 | cd ./repo 104 | git checkout -b "$commit_branch" 105 | fi 106 | 107 | git config user.email "$(params.git_user_email)" 108 | git config user.name "$(params.git_user_name)" 109 | 110 | mkdir -p $(params.sub_path) && rm -rf $(params.sub_path)/* 111 | cd $(params.sub_path) 112 | 113 | echo '$(params.git_files)' | base64 --decode > files.json 114 | eval "$(cat files.json | jq -r 'to_entries | .[] | @sh "mkdir -p $(dirname \(.key)) && echo \(.value) > \(.key) && git add \(.key)"')" 115 | 116 | git commit -m "$(params.git_commit_message)" 117 | git push origin $commit_branch 118 | 119 | echo "$commit_branch" > /workspaces/ws/commit_branch 120 | 121 | - name: ensure-base-branch-exists 122 | image: tapsme/config-writer 123 | securityContext: 124 | runAsUser: 0 125 | workingDir: /root 126 | script: | 127 | #!/usr/bin/env bash 128 | 129 | set -o errexit 130 | set -o pipefail 131 | 132 | set +o xtrace # Avoid leaking secrets, echo sensitive lines 133 | 134 | echo 'git_prefix=$(cat $(credentials.path)/.git-credentials)' 135 | git_prefix=$(cat $(credentials.path)/.git-credentials) 136 | 137 | echo 'git_repository="$git_prefix/$(params.repository_owner)/$(params.repository_name).git"' 138 | git_repository="$git_prefix/$(params.repository_owner)/$(params.repository_name).git" 139 | 140 | echo 'git clone --depth 1 -b "$commit_branch" "$git_repository" ./repo 2>&1 | sed "s|$git_prefix|REDACTED|g' 141 | git clone --depth 1 "$git_repository" ./repo 2>&1 | sed "s|$git_prefix|REDACTED|g" 142 | 143 | set -o xtrace 144 | cd ./repo 145 | 146 | if git show-ref --verify --quiet "refs/heads/$(params.base_branch)"; then 147 | echo "branch exists" 148 | else 149 | git checkout --orphan "$(params.base_branch)" 150 | git rm --cached . -r || true 151 | git config user.email "$(params.git_user_email)" 152 | git config user.name "$(params.git_user_name)" 153 | git commit -m "Initialize branch" --allow-empty 154 | git push origin $(params.base_branch) 155 | fi 156 | 157 | - name: open-pr 158 | image: tapsme/jx-scm 159 | script: | 160 | #!/usr/bin/env bash 161 | 162 | set -o errexit 163 | set -o pipefail 164 | 165 | head_branch=$(cat /workspaces/ws/commit_branch | tr -d '\n') 166 | 167 | token=$(cat $(credentials.path)/.git-credentials | sed -e 's/https:.*://' | sed -e 's/@.*//') 168 | echo $token 169 | jx-scm pull-request create \ 170 | --kind "$(params.git_server_kind)" \ 171 | --server "$(params.git_server_address)" \ 172 | --username "$(params.git_user_name)" \ 173 | --token "$token" \ 174 | --owner "$(params.repository_owner)" \ 175 | --name "$(params.repository_name)" \ 176 | --head "$head_branch" \ 177 | --title "$(params.pull_request_title)" \ 178 | --body "$(params.pull_request_body)" \ 179 | --base "$(params.base_branch)" \ 180 | --allow-update 2>&1 | 181 | tee stdoutAndSterr.txt 182 | 183 | cat stdoutAndSterr.txt | sed -n -e 's/^.*\. url: //p' > $(results.pr-url.path) 184 | -------------------------------------------------------------------------------- /multi-language-support-with-sonar/clusterdelivery/deliverable-config-writer/commit-and-pr-taskrun-runtemplate.yaml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | 3 | --- 4 | apiVersion: carto.run/v1alpha1 5 | kind: ClusterRunTemplate 6 | metadata: 7 | name: commit-and-pr-pipelinerun-prod 8 | spec: 9 | outputs: 10 | pr-url: status.taskResults[?(@.name=="pr-url")].value 11 | template: 12 | apiVersion: tekton.dev/v1beta1 13 | kind: TaskRun 14 | metadata: 15 | generateName: $(runnable.metadata.name)$-commit-and-pr- 16 | labels: $(runnable.metadata.labels)$ 17 | spec: 18 | serviceAccountName: $(runnable.spec.inputs.serviceAccount)$ 19 | taskRef: 20 | name: commit-and-pr 21 | kind: ClusterTask 22 | workspaces: 23 | - name: ws 24 | emptyDir: { } 25 | params: 26 | - name: git_server_kind 27 | value: $(runnable.spec.inputs.git_server_kind)$ 28 | - name: git_server_address 29 | value: $(runnable.spec.inputs.git_server_address)$ 30 | - name: repository_owner 31 | value: $(runnable.spec.inputs.repository_owner)$ 32 | - name: repository_name 33 | value: $(runnable.spec.inputs.repository_name)$ 34 | - name: commit_branch 35 | value: $(runnable.spec.inputs.commit_branch)$ 36 | - name: pull_request_title 37 | value: $(runnable.spec.inputs.pull_request_title)$ 38 | - name: pull_request_body 39 | value: $(runnable.spec.inputs.pull_request_body)$ 40 | - name: base_branch 41 | value: $(runnable.spec.inputs.base_branch)$ 42 | - name: git_user_name 43 | value: $(runnable.spec.inputs.git_user_name)$ 44 | - name: git_user_email 45 | value: $(runnable.spec.inputs.git_user_email)$ 46 | - name: git_commit_message 47 | value: $(runnable.spec.inputs.git_commit_message)$ 48 | - name: git_files 49 | value: $(runnable.spec.inputs.git_files)$ 50 | - name: sub_path 51 | value: $(runnable.spec.inputs.sub_path)$ 52 | -------------------------------------------------------------------------------- /multi-language-support-with-sonar/clusterdelivery/deliverable-config-writer/config-writer-and-pull-requester-template.yaml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | 3 | --- 4 | apiVersion: carto.run/v1alpha1 5 | kind: ClusterTemplate 6 | metadata: 7 | name: deliverable-config-writer-and-pr-template 8 | spec: 9 | ytt: | 10 | #@ load("@ytt:data", "data") 11 | #@ load("@ytt:json", "json") 12 | #@ load("@ytt:base64", "base64") 13 | 14 | #@ def merge_labels(fixed_values): 15 | #@ labels = {} 16 | #@ if hasattr(data.values.deliverable.metadata, "labels"): 17 | #@ labels.update(data.values.deliverable.metadata.labels) 18 | #@ end 19 | #@ labels.update(fixed_values) 20 | #@ return labels 21 | #@ end 22 | 23 | --- 24 | apiVersion: carto.run/v1alpha1 25 | kind: Runnable 26 | metadata: 27 | name: #@ data.values.deliverable.metadata.name + "-config-writer-pull-requester" 28 | labels: #@ merge_labels({ "app.kubernetes.io/component": "config-writer-pull-requester" }) 29 | spec: 30 | #@ if/end hasattr(data.values.deliverable.spec, "serviceAccountName"): 31 | serviceAccountName: #@ data.values.deliverable.spec.serviceAccountName 32 | 33 | runTemplateRef: 34 | name: commit-and-pr-pipelinerun 35 | 36 | inputs: 37 | serviceAccount: #@ data.values.params.serviceAccount 38 | git_server_kind: "github" 39 | git_server_address: "https://github.com" 40 | commit_branch: "" 41 | pull_request_title: #@ "ready for review, delivery revision: " + data.values.source.revision 42 | pull_request_body: "generated by supply chain" 43 | repository_owner: #@ data.values.params.deliverable_repository_owner 44 | repository_name: #@ data.values.params.deliverable_repository_name 45 | base_branch: "main" 46 | git_user_name: "supplychain" 47 | git_user_email: "supplychain@cluster.local" 48 | git_commit_message: "supply chain promoted workload" 49 | git_files: #@ base64.encode(json.encode(data.values.config)) 50 | sub_path: #@ "config/" + data.values.deliverable.metadata.namespace + "/" + data.values.deliverable.metadata.name 51 | -------------------------------------------------------------------------------- /multi-language-support-with-sonar/clusterdelivery/deliverable-config/config-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterConfigTemplate 3 | metadata: 4 | name: config-deliverable-template 5 | spec: 6 | configPath: .data 7 | ytt: | 8 | #@ load("@ytt:data", "data") 9 | #@ load("@ytt:yaml", "yaml") 10 | 11 | #@ def has_git_params(): 12 | #@ if 'gitops_repository_prefix' in data.values.params: 13 | #@ return True 14 | #@ end 15 | #@ 16 | #@ if 'gitops_repository' in data.values.params: 17 | #@ return True 18 | #@ end 19 | #@ 20 | #@ return False 21 | #@ end 22 | 23 | #@ def is_gitops(): 24 | #@ return has_git_params() 25 | #@ end 26 | 27 | #@ def param(key): 28 | #@ if not key in data.values.params: 29 | #@ return None 30 | #@ end 31 | #@ return data.values.params[key] 32 | #@ end 33 | 34 | #@ def strip_trailing_slash(some_string): 35 | #@ if some_string[-1] == "/": 36 | #@ return some_string[:-1] 37 | #@ end 38 | #@ return some_string 39 | #@ end 40 | 41 | #@ def deliverable(): 42 | apiVersion: carto.run/v1alpha1 43 | kind: Deliverable 44 | metadata: 45 | name: #@ data.values.deliverable.metadata.name 46 | namespace: #@ data.values.deliverable.metadata.namespace 47 | labels: 48 | app.kubernetes.io/component: deliverable 49 | app.tanzu.vmware.com/deliverable-type: web 50 | app.tanzu.vmware.com/delivery-commit-sha: #@ data.values.source.revision 51 | spec: 52 | #@ if/end hasattr(data.values.deliverable.spec, "serviceAccountName"): 53 | serviceAccountName: #@ data.values.deliverable.spec.serviceAccountName 54 | 55 | params: 56 | - name: "gitops_ssh_secret" 57 | value: #@ param("gitops_ssh_secret") 58 | - name: "gitops_sub_path" 59 | value: #@ "config/" + data.values.deliverable.metadata.namespace + "/" + data.values.deliverable.metadata.name 60 | 61 | source: 62 | git: 63 | url: #@ data.values.deliverable.spec.source.git.url 64 | ref: 65 | branch: main 66 | #@ end 67 | 68 | --- 69 | apiVersion: v1 70 | kind: ConfigMap 71 | metadata: 72 | name: #@ data.values.deliverable.metadata.name + "-deliverable" 73 | labels: 74 | app.kubernetes.io/component: config 75 | data: 76 | #@yaml/text-templated-strings 77 | (@= data.values.deliverable.metadata.name @)-(@= data.values.deliverable.metadata.namespace @)-deliverable.yml: #@ yaml.encode(deliverable()) -------------------------------------------------------------------------------- /multi-language-support-with-sonar/clusterdelivery/delivery.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | --- 3 | apiVersion: carto.run/v1alpha1 4 | kind: ClusterDelivery 5 | metadata: 6 | name: delivery-with-code-promotion 7 | spec: 8 | params: 9 | - name: deliverable_repository_owner 10 | default: Mpluya 11 | - name: deliverable_repository_name 12 | default: config-deliverable-prod 13 | selector: 14 | app.tanzu.vmware.com/deliverable-type: web 15 | deliverable-intent: code-promotion 16 | resources: 17 | - name: source-provider 18 | templateRef: 19 | kind: ClusterSourceTemplate 20 | name: delivery-source-template 21 | params: 22 | - name: serviceAccount 23 | value: default 24 | - name: gitImplementation 25 | value: go-git 26 | 27 | - name: deployer 28 | templateRef: 29 | kind: ClusterDeploymentTemplate 30 | name: app-deploy 31 | params: 32 | - name: serviceAccount 33 | value: default 34 | deployment: 35 | resource: source-provider 36 | 37 | - configs: 38 | name: prod-deliverable-config 39 | sources: 40 | - name: source 41 | resource: source-provider 42 | templateRef: 43 | kind: ClusterConfigTemplate 44 | name: config-deliverable-template 45 | 46 | - name: prod-deliverable-config-writer-and-pr 47 | configs: 48 | - name: config 49 | resource: prod-deliverable-config 50 | sources: 51 | - name: source 52 | resource: source-provider 53 | params: 54 | - name: serviceAccount 55 | value: default 56 | templateRef: 57 | kind: ClusterTemplate 58 | name: deliverable-config-writer-and-pr-template -------------------------------------------------------------------------------- /multi-language-support-with-sonar/supplychain/deliverable-config-writer/cluster-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterTemplate 3 | metadata: 4 | labels: 5 | name: config-writer-deliverable-template 6 | spec: 7 | params: 8 | - default: default 9 | name: serviceAccount 10 | ytt: | 11 | #@ load("@ytt:data", "data") 12 | #@ load("@ytt:json", "json") 13 | #@ load("@ytt:base64", "base64") 14 | #@ load("@ytt:assert", "assert") 15 | 16 | #@ def merge_labels(fixed_values): 17 | #@ labels = {} 18 | #@ if hasattr(data.values.workload.metadata, "labels"): 19 | #@ labels.update(data.values.workload.metadata.labels) 20 | #@ end 21 | #@ labels.update(fixed_values) 22 | #@ return labels 23 | #@ end 24 | 25 | #@ def is_monorepo_approach(): 26 | #@ if 'gitops_server_address' in data.values.params and 'gitops_repository_owner' in data.values.params and 'gitops_repository_name' in data.values.params: 27 | #@ return True 28 | #@ end 29 | #@ if 'gitops_server_address' in data.values.params or 'gitops_repository_owner' in data.values.params or 'gitops_repository_name' in data.values.params: 30 | #@ 'gitops_server_address' in data.values.params or assert.fail("missing param: gitops_server_address") 31 | #@ 'gitops_repository_owner' in data.values.params or assert.fail("missing param: gitops_repository_owner") 32 | #@ 'gitops_repository_name' in data.values.params or assert.fail("missing param: gitops_repository_name") 33 | #@ end 34 | #@ return False 35 | #@ end 36 | 37 | #@ def has_git_params(): 38 | #@ if 'gitops_repository_prefix' in data.values.params: 39 | #@ return True 40 | #@ end 41 | #@ 42 | #@ if 'gitops_repository' in data.values.params: 43 | #@ return True 44 | #@ end 45 | #@ 46 | #@ return False 47 | #@ end 48 | 49 | #@ def is_gitops(): 50 | #@ return is_monorepo_approach() or has_git_params() 51 | #@ end 52 | 53 | #@ def param(key): 54 | #@ if not key in data.values.params: 55 | #@ return None 56 | #@ end 57 | #@ return data.values.params[key] 58 | #@ end 59 | 60 | #@ def strip_trailing_slash(some_string): 61 | #@ if some_string[-1] == "/": 62 | #@ return some_string[:-1] 63 | #@ end 64 | #@ return some_string 65 | #@ end 66 | 67 | #@ def mono_repository(): 68 | #@ strip_trailing_slash(data.values.params.gitops_server_address) 69 | #@ return "/".join([ 70 | #@ strip_trailing_slash(data.values.params.gitops_server_address), 71 | #@ strip_trailing_slash(data.values.params.gitops_repository_owner), 72 | #@ data.values.params.gitops_repository_name, 73 | #@ ]) + ".git" 74 | #@ end 75 | 76 | #@ def git_repository(): 77 | #@ if is_monorepo_approach(): 78 | #@ return mono_repository() 79 | #@ end 80 | #@ 81 | #@ if 'gitops_repository' in data.values.params: 82 | #@ return param("gitops_repository") 83 | #@ end 84 | #@ 85 | #@ prefix = param("gitops_repository_prefix") 86 | #@ return prefix + data.values.workload.metadata.name + ".git" 87 | #@ end 88 | --- 89 | apiVersion: carto.run/v1alpha1 90 | kind: Runnable 91 | metadata: 92 | name: #@ data.values.workload.metadata.name + "-deliverable-config-writer" 93 | labels: 94 | app.kubernetes.io/component: config-writer 95 | #@ if/end hasattr(data.values.workload.metadata, "labels") and hasattr(data.values.workload.metadata.labels, "app.kubernetes.io/part-of"): 96 | app.kubernetes.io/part-of: #@ data.values.workload.metadata.labels["app.kubernetes.io/part-of"] 97 | spec: 98 | #@ if/end hasattr(data.values.workload.spec, "serviceAccountName"): 99 | serviceAccountName: #@ data.values.workload.spec.serviceAccountName 100 | 101 | runTemplateRef: 102 | name: tekton-taskrun 103 | 104 | inputs: 105 | serviceAccount: #@ data.values.params.serviceAccount 106 | taskRef: 107 | kind: ClusterTask 108 | name: #@ "git-writer" 109 | params: 110 | - name: git_repository 111 | value: #@ param("deliverable_repository") 112 | - name: git_branch 113 | value: #@ param("deliverable_branch") 114 | - name: git_user_name 115 | value: #@ param("gitops_user_name") 116 | - name: git_user_email 117 | value: #@ param("gitops_user_email") 118 | - name: git_commit_message 119 | value: #@ param("gitops_commit_message") 120 | - name: git_files 121 | value: #@ base64.encode(json.encode(data.values.config)) 122 | #@ if/end is_monorepo_approach(): 123 | - name: sub_path 124 | value: #@ "config/" + data.values.workload.metadata.namespace + "/" + data.values.workload.metadata.name -------------------------------------------------------------------------------- /multi-language-support-with-sonar/supplychain/deliverable-config/config-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterConfigTemplate 3 | metadata: 4 | name: config-deliverable-template 5 | spec: 6 | configPath: .data 7 | ytt: | 8 | #@ load("@ytt:data", "data") 9 | #@ load("@ytt:yaml", "yaml") 10 | 11 | #@ def has_git_params(): 12 | #@ if 'gitops_repository_prefix' in data.values.params: 13 | #@ return True 14 | #@ end 15 | #@ 16 | #@ if 'gitops_repository' in data.values.params: 17 | #@ return True 18 | #@ end 19 | #@ 20 | #@ return False 21 | #@ end 22 | 23 | #@ def is_gitops(): 24 | #@ return has_git_params() 25 | #@ end 26 | 27 | #@ def param(key): 28 | #@ if not key in data.values.params: 29 | #@ return None 30 | #@ end 31 | #@ return data.values.params[key] 32 | #@ end 33 | 34 | #@ def strip_trailing_slash(some_string): 35 | #@ if some_string[-1] == "/": 36 | #@ return some_string[:-1] 37 | #@ end 38 | #@ return some_string 39 | #@ end 40 | 41 | #@ def git_repository(): 42 | #@ strip_trailing_slash(data.values.params.gitops_server_address) 43 | #@ return "/".join([ 44 | #@ strip_trailing_slash(data.values.params.gitops_server_address), 45 | #@ strip_trailing_slash(data.values.params.gitops_repository_owner), 46 | #@ data.values.params.gitops_repository_name, 47 | #@ ]) + ".git" 48 | #@ end 49 | 50 | 51 | #@ def merge_labels(fixed_values): 52 | #@ labels = {} 53 | #@ if hasattr(data.values.workload.metadata, "labels"): 54 | #@ labels.update(data.values.workload.metadata.labels) 55 | #@ end 56 | #@ labels.update(fixed_values) 57 | #@ return labels 58 | #@ end 59 | 60 | #@ def deliverable(): 61 | apiVersion: carto.run/v1alpha1 62 | kind: Deliverable 63 | metadata: 64 | name: #@ data.values.workload.metadata.name 65 | namespace: #@ data.values.workload.metadata.namespace 66 | labels: #@ merge_labels({ "app.kubernetes.io/component": "deliverable", "app.tanzu.vmware.com/deliverable-type": "web", "deliverable-intent": "code-promotion" }) 67 | spec: 68 | #@ if/end hasattr(data.values.workload.spec, "serviceAccountName"): 69 | serviceAccountName: #@ data.values.workload.spec.serviceAccountName 70 | 71 | params: 72 | - name: "gitops_ssh_secret" 73 | value: #@ param("gitops_ssh_secret") 74 | - name: "gitops_sub_path" 75 | value: #@ "config/" + data.values.workload.metadata.namespace + "/" + data.values.workload.metadata.name 76 | 77 | source: 78 | git: 79 | url: #@ git_repository() 80 | ref: 81 | branch: #@ param("gitops_branch") 82 | #@ end 83 | 84 | --- 85 | apiVersion: v1 86 | kind: ConfigMap 87 | metadata: 88 | name: #@ data.values.workload.metadata.name + "-deliverable" 89 | labels: #@ merge_labels({ "app.kubernetes.io/component": "config" }) 90 | data: 91 | #@yaml/text-templated-strings 92 | (@= data.values.workload.metadata.name @)-(@= data.values.workload.metadata.namespace @)-deliverable.yml: #@ yaml.encode(deliverable()) -------------------------------------------------------------------------------- /multi-language-support-with-sonar/supplychain/source-analyzer/run-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterRunTemplate 3 | metadata: 4 | name: tekton-sonarqube-taskrun 5 | labels: 6 | apps.tanzu.vmware.com/sonarqube: "sonarqube" 7 | spec: 8 | outputs: 9 | revision: spec.params[?(@.name=="source-revision")].value 10 | url: spec.params[?(@.name=="source-url")].value 11 | 12 | 13 | template: 14 | apiVersion: tekton.dev/v1beta1 15 | kind: TaskRun 16 | metadata: 17 | generateName: code-analysis-$(runnable.metadata.name)$- 18 | labels: $(runnable.metadata.labels)$ 19 | spec: 20 | serviceAccountName: $(runnable.spec.inputs.serviceAccount)$ 21 | params: 22 | - name: source-url 23 | value: $(runnable.spec.inputs.source-url)$ 24 | - name: source-revision 25 | value: $(runnable.spec.inputs.source-revision)$ 26 | - name: SONAR_HOST_URL 27 | value: http://sonarqube.cvsdr.tapsme.org 28 | - name: SONAR_PROJECT_KEY 29 | value: $(runnable.spec.inputs.sonar-project-key)$ 30 | - name: SONAR_LOGIN 31 | value: squ_689ee47bf781dd85e7d290025fe3fd4d4ffb1c15 32 | - name: WAIT_ON_SONAR_ANALYSIS 33 | value: $(runnable.spec.inputs.wait_on_sonar_analysis)$ 34 | 35 | taskRef: 36 | name: $(selected.metadata.name)$ 37 | 38 | workspaces: 39 | - name: custom-maven-settings 40 | secret: 41 | secretName: maven-settings 42 | - name: maven-settings 43 | subPath: maven-repo-cache 44 | persistentVolumeClaim: 45 | claimName: supplychainpvc 46 | - name: supplychain-workspace 47 | emptyDir: {} -------------------------------------------------------------------------------- /multi-language-support-with-sonar/supplychain/source-analyzer/source-template.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterSourceTemplate 3 | metadata: 4 | annotations: 5 | name: sonarqube-template 6 | spec: 7 | params: 8 | - name: wait_on_sonar_analysis 9 | default: {} 10 | revisionPath: .status.outputs.revision 11 | urlPath: .status.outputs.url 12 | 13 | ytt: | 14 | #@ load("@ytt:data", "data") 15 | 16 | #@ def merge_labels(fixed_values): 17 | #@ labels = {} 18 | #@ if hasattr(data.values.workload.metadata, "labels"): 19 | #@ labels.update(data.values.workload.metadata.labels) 20 | #@ end 21 | #@ labels.update(fixed_values) 22 | #@ return labels 23 | #@ end 24 | 25 | apiVersion: carto.run/v1alpha1 26 | kind: Runnable 27 | metadata: 28 | name: #@ data.values.workload.metadata.name + "-code-analysis" 29 | labels: #@ merge_labels({ "app.kubernetes.io/component": "test" }) 30 | spec: 31 | #@ if/end hasattr(data.values.workload.spec, "serviceAccountName"): 32 | serviceAccountName: #@ data.values.workload.spec.serviceAccountName 33 | 34 | runTemplateRef: 35 | name: tekton-sonarqube-taskrun 36 | kind: ClusterRunTemplate 37 | 38 | selector: 39 | resource: 40 | apiVersion: tekton.dev/v1beta1 41 | kind: Task 42 | matchingLabels: 43 | apps.tanzu.vmware.com/sonarqube: "sonarqube" 44 | apps.tanzu.vmware.com/language: #@ data.values.workload.metadata.labels["apps.tanzu.vmware.com/language"] 45 | 46 | inputs: 47 | source-url: #@ data.values.source.url 48 | source-revision: #@ data.values.source.revision 49 | 50 | #@ if hasattr(data.values.workload.spec, "serviceAccountName"): 51 | serviceAccount: #@ data.values.workload.spec.serviceAccountName 52 | #@ else: 53 | serviceAccount: default 54 | #@ end 55 | 56 | sonar-project-key: #@ data.values.workload.metadata.name 57 | wait_on_sonar_analysis: #@ data.values.params.wait_on_sonar_analysis -------------------------------------------------------------------------------- /multi-language-support-with-sonar/supplychain/source-analyzer/task-dotnet.yml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | name: sonarqube-scanner-dotnet 5 | namespace: default 6 | labels: 7 | apps.tanzu.vmware.com/language: "dotnet" 8 | apps.tanzu.vmware.com/sonarqube: "sonarqube" 9 | annotations: 10 | tekton.dev/pipelines.minVersion: "0.12.1" 11 | tekton.dev/categories: Security 12 | tekton.dev/tags: security 13 | tekton.dev/displayName: "sonarqube scanner" 14 | tekton.dev/platforms: "linux/amd64" 15 | spec: 16 | params: 17 | - name: SONAR_HOST_URL 18 | description: Host URL where the sonarqube server is running 19 | default: "" 20 | - name: SONAR_PROJECT_KEY 21 | description: Project's unique key 22 | default: "" 23 | - name: SONAR_LOGIN 24 | description: Auth for the project 25 | default: "" 26 | - name: source-url 27 | description: Location of the source code 28 | - name: source-revision 29 | description: i.e. git hash 30 | default: "" 31 | - name: WAIT_ON_SONAR_ANALYSIS 32 | description: toggle to wait until sonarqube analysis is complete 33 | 34 | workspaces: 35 | - name: maven-settings 36 | - name: supplychain-workspace 37 | 38 | 39 | steps: 40 | - name: pull-code 41 | image: index.docker.io/tapsme/gradle@sha256:ba5d54bc93e3d7ae95481963c4cbd171100804a4fc64baf2ebabf0329c9e1179 42 | workingDir: $(workspaces.supplychain-workspace.path) 43 | script: | 44 | #!/usr/bin/env bash 45 | set -ex 46 | wget -qO- $(params.source-url) | tar xvz 47 | 48 | - name: sonar-scan 49 | image: index.docker.io/tapsme/dotnetsonar@sha256:0122ff42df5e2121ad3100dfca309e2f9cdf06d545d6e031f3e70f332b871a18 50 | workingDir: $(workspaces.supplychain-workspace.path) 51 | script: | 52 | #!/usr/bin/env bash 53 | set -ex 54 | dotnet-sonarscanner begin /k:$(params.SONAR_PROJECT_KEY) /d:sonar.host.url=$(params.SONAR_HOST_URL) /d:sonar.login=$(params.SONAR_LOGIN) 55 | dotnet build *.sln 56 | dotnet-sonarscanner end /d:sonar.login=$(params.SONAR_LOGIN) -------------------------------------------------------------------------------- /multi-language-support-with-sonar/supplychain/source-analyzer/task.yml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | name: sonarqube-scanner 5 | namespace: default 6 | labels: 7 | apps.tanzu.vmware.com/language: "java" 8 | apps.tanzu.vmware.com/sonarqube: "sonarqube" 9 | annotations: 10 | tekton.dev/pipelines.minVersion: "0.12.1" 11 | tekton.dev/categories: Security 12 | tekton.dev/tags: security 13 | tekton.dev/displayName: "sonarqube scanner" 14 | tekton.dev/platforms: "linux/amd64" 15 | spec: 16 | params: 17 | - name: SONAR_HOST_URL 18 | description: Host URL where the sonarqube server is running 19 | default: "" 20 | - name: SONAR_PROJECT_KEY 21 | description: Project's unique key 22 | default: "" 23 | - name: SONAR_LOGIN 24 | description: Auth for the project 25 | default: "" 26 | - name: source-url 27 | description: Location of the source code 28 | - name: source-revision 29 | description: i.e. git hash 30 | default: "" 31 | - name: WAIT_ON_SONAR_ANALYSIS 32 | description: toggle to wait until sonarqube analysis is complete 33 | 34 | workspaces: 35 | - name: custom-maven-settings 36 | - name: maven-settings 37 | - name: supplychain-workspace 38 | 39 | steps: 40 | - name: compile 41 | image: index.docker.io/tapsme/gradle@sha256:ba5d54bc93e3d7ae95481963c4cbd171100804a4fc64baf2ebabf0329c9e1179 42 | workingDir: $(workspaces.supplychain-workspace.path) 43 | script: | 44 | #!/usr/bin/env bash 45 | set -ex 46 | wget -qO- $(params.source-url) | tar xvz 47 | ./mvnw compile -Dmaven.repo.local=$(workspaces.maven-settings.path) -s $(workspaces.custom-maven-settings.path)/settings.xml 48 | - name: sonar-properties-create 49 | image: index.docker.io/tapsme/gradle@sha256:ba5d54bc93e3d7ae95481963c4cbd171100804a4fc64baf2ebabf0329c9e1179 50 | workingDir: $(workspaces.supplychain-workspace.path) 51 | script: | 52 | #!/usr/bin/env bash 53 | replaceValues() { 54 | filename=$1 55 | thekey=$2 56 | newvalue=$3 57 | if ! grep -R "^[#]*\s*${thekey}=.*" $filename >/dev/null; then 58 | echo "APPENDING because '${thekey}' not found" 59 | echo "" >>$filename 60 | echo "$thekey=$newvalue" >>$filename 61 | else 62 | echo "SETTING because '${thekey}' found already" 63 | sed -ir "s|^[#]*\s*${thekey}=.*|$thekey=$newvalue|" $filename 64 | fi 65 | } 66 | 67 | # If we were given a properties file, then use that. 68 | if [[ -f $(workspaces.supplychain-workspace.path)/sonar-project.properties ]]; then 69 | echo "using user provided sonar-project.properties file" 70 | cp -RL $(workspaces.supplychain-workspace.path)/sonar-project.properties $(workspaces.supplychain-workspace.path)/sonar-project.properties 71 | fi 72 | if [[ -f $(workspaces.supplychain-workspace.path)/sonar-project.properties ]]; then 73 | 74 | # Allow overrides from parameters passed in from the supply chain. 75 | if [[ -n "$(params.SONAR_HOST_URL)" ]]; then 76 | replaceValues $(workspaces.supplychain-workspace.path)/sonar-project.properties sonar.host.url $(params.SONAR_HOST_URL) 77 | fi 78 | if [[ -n "$(params.SONAR_PROJECT_KEY)" ]]; then 79 | replaceValues $(workspaces.supplychain-workspace.path)/sonar-project.properties sonar.projectKey $(params.SONAR_PROJECT_KEY) 80 | fi 81 | if [[ -n "$(params.SONAR_LOGIN)" ]]; then 82 | replaceValues $(workspaces.supplychain-workspace.path)/sonar-project.properties sonar.login $(params.SONAR_LOGIN) 83 | fi 84 | else 85 | touch sonar-project.properties 86 | echo "sonar.projectKey=$(params.SONAR_PROJECT_KEY)" >> sonar-project.properties 87 | echo "sonar.host.url=$(params.SONAR_HOST_URL)" >> sonar-project.properties 88 | echo "sonar.login=$(params.SONAR_LOGIN)" >> sonar-project.properties 89 | echo "sonar.sources=." >> sonar-project.properties 90 | fi 91 | echo "---------------------------" 92 | cat $(workspaces.supplychain-workspace.path)/sonar-project.properties 93 | 94 | - name: sonar-scan 95 | image: index.docker.io/tapsme/sonar-scanner-cli@sha256:b8c95a37025f3c13162118cd55761ea0b2a13d1837f9deec51b7b6d82c52040a 96 | workingDir: $(workspaces.supplychain-workspace.path) 97 | command: 98 | - sonar-scanner 99 | 100 | - name: quality-gate 101 | image: index.docker.io/tapsme/alpine-bash-curl-jq@sha256:a5369f1e4e9d139ed6a4064686cd0ff57a75f8d1e928944c540fe753c332acfd 102 | workingDir: $(workspaces.supplychain-workspace.path) 103 | script: | 104 | #!/usr/bin/env bash 105 | if [ -z "$(params.WAIT_ON_SONAR_ANALYSIS)" ] || [ "$(params.WAIT_ON_SONAR_ANALYSIS)" == "false" ]; then 106 | echo "not waiting for analysis to finish" 107 | exit 0 108 | fi 109 | 110 | metadataFile=$(workspaces.supplychain-workspace.path)/.scannerwork/report-task.txt 111 | sonarPropsFile=$(workspaces.supplychain-workspace.path)/sonar-project.properties 112 | if [[ ! -f "$metadataFile" ]]; then 113 | echo "$metadataFile does not exist." 114 | exit 1 115 | fi 116 | 117 | cat $metadataFile 118 | serverUrl="$(sed -n 's/serverUrl=\(.*\)/\1/p' "${metadataFile}")" 119 | ceTaskUrl="$(sed -n 's/ceTaskUrl=\(.*\)/\1/p' "${metadataFile}")" 120 | sonarToken="$(sed -n 's/sonar.login=\(.*\)/\1/p' "${sonarPropsFile}")" 121 | 122 | if [ -z "${serverUrl}" ] || [ -z "${ceTaskUrl}" ]; then 123 | echo "Invalid report metadata file." 124 | exit 1 125 | fi 126 | 127 | task="$(curl --silent --fail --show-error --user "${sonarToken}": "${ceTaskUrl}")" 128 | status="$(jq -r '.task.status' <<< "$task")" 129 | 130 | until [[ ${status} != "PENDING" && ${status} != "IN_PROGRESS" ]]; do 131 | printf '.' 132 | sleep 5s 133 | task="$(curl --silent --fail --show-error --user "${sonarToken}": "${ceTaskUrl}")" 134 | status="$(jq -r '.task.status' <<< "$task")" 135 | done 136 | 137 | analysisId="$(jq -r '.task.analysisId' <<< "${task}")" 138 | echo "analysisId: " $analysisId 139 | 140 | qualityGateUrl="${serverUrl}/api/qualitygates/project_status?analysisId=${analysisId}" 141 | 142 | qualityGateStatus="$(curl --silent --fail --show-error --user "${sonarToken}": "${qualityGateUrl}" | jq -r '.projectStatus.status')" 143 | 144 | if [[ ${qualityGateStatus} == "OK" ]]; then 145 | echo "quality-gate-status::PASSED" 146 | elif [[ ${qualityGateStatus} == "WARN" ]]; then 147 | echo "quality-gate-status::WARN" 148 | elif [[ ${qualityGateStatus} == "ERROR" ]]; then 149 | echo "quality-gate-status::FAILED" 150 | exit 1 151 | else 152 | echo "quality-gate-status::FAILED" 153 | exit 1 154 | fi -------------------------------------------------------------------------------- /multi-language-support-with-sonar/supplychain/source-test-analyze-scan-to-url.yml: -------------------------------------------------------------------------------- 1 | apiVersion: carto.run/v1alpha1 2 | kind: ClusterSupplyChain 3 | metadata: 4 | name: source-test-analyze-scan-to-url 5 | spec: 6 | params: 7 | - name: deliverable_repository 8 | default: ssh://git@github.com/Mpluya/polaris-run-qa-deliverable.git 9 | - name: deliverable_branch 10 | default: main 11 | - name: maven_repository_url 12 | value: https://repo.maven.apache.org/maven2 13 | - default: main 14 | name: gitops_branch 15 | - default: supplychain 16 | name: gitops_user_name 17 | - default: supplychain 18 | name: gitops_user_email 19 | - default: supplychain@cluster.local 20 | name: gitops_commit_message 21 | - default: "gitops-ssh" 22 | name: gitops_ssh_secret 23 | - default: ssh://git@github.com 24 | name: gitops_server_address 25 | - default: Mpluya 26 | name: gitops_repository_owner 27 | - default: config-polaris-demo 28 | name: gitops_repository_name 29 | - default: github 30 | name: gitops_pull_request_server_kind 31 | - default: "" 32 | name: gitops_commit_branch 33 | - default: ready for review 34 | name: gitops_pull_request_title 35 | - default: generated by supply chain 36 | name: gitops_pull_request_body 37 | resources: 38 | - name: source-provider 39 | params: 40 | - name: serviceAccount 41 | value: default 42 | - name: gitImplementation 43 | value: go-git 44 | templateRef: 45 | kind: ClusterSourceTemplate 46 | name: source-template 47 | 48 | - name: source-tester 49 | sources: 50 | - name: source 51 | resource: source-provider 52 | templateRef: 53 | kind: ClusterSourceTemplate 54 | name: testing-pipeline 55 | 56 | 57 | - name: source-scanner 58 | params: 59 | - default: scan-policy 60 | name: scanning_source_policy 61 | - default: blob-source-scan-template 62 | name: scanning_source_template 63 | sources: 64 | - name: source 65 | resource: source-tester 66 | templateRef: 67 | kind: ClusterSourceTemplate 68 | name: source-scanner-template 69 | - name: image-builder 70 | params: 71 | - name: serviceAccount 72 | value: default 73 | - name: registry 74 | value: 75 | ca_cert_data: "" 76 | repository: tapsme 77 | server: index.docker.io 78 | - default: default 79 | name: clusterBuilder 80 | - default: ./Dockerfile 81 | name: dockerfile 82 | - default: ./ 83 | name: docker_build_context 84 | - default: [] 85 | name: docker_build_extra_args 86 | sources: 87 | - name: source 88 | resource: source-scanner 89 | templateRef: 90 | kind: ClusterImageTemplate 91 | options: 92 | - name: kpack-template 93 | selector: 94 | matchFields: 95 | - key: spec.params[?(@.name=="dockerfile")] 96 | operator: DoesNotExist 97 | - name: kaniko-template 98 | selector: 99 | matchFields: 100 | - key: spec.params[?(@.name=="dockerfile")] 101 | operator: Exists 102 | - images: 103 | - name: image 104 | resource: image-builder 105 | name: image-scanner 106 | params: 107 | - default: snyk-scan-policy 108 | name: scanning_image_policy 109 | - default: snyk-private-image-scan-template 110 | name: scanning_image_template 111 | templateRef: 112 | kind: ClusterImageTemplate 113 | name: image-scanner-template 114 | - images: 115 | - name: image 116 | resource: image-scanner 117 | name: config-provider 118 | params: 119 | - name: serviceAccount 120 | value: default 121 | templateRef: 122 | kind: ClusterConfigTemplate 123 | name: convention-template 124 | - configs: 125 | - name: config 126 | resource: config-provider 127 | name: app-config 128 | templateRef: 129 | kind: ClusterConfigTemplate 130 | name: config-template 131 | - configs: 132 | - name: config 133 | resource: app-config 134 | name: config-writer 135 | params: 136 | - name: serviceAccount 137 | value: default 138 | - name: registry 139 | value: 140 | ca_cert_data: "" 141 | repository: tapsme 142 | server: index.docker.io 143 | templateRef: 144 | kind: ClusterTemplate 145 | name: config-writer-template 146 | 147 | - configs: 148 | name: deliverable-config 149 | templateRef: 150 | kind: ClusterConfigTemplate 151 | name: config-deliverable-template 152 | 153 | - name: deliverable-config-writer 154 | configs: 155 | - name: config 156 | resource: deliverable-config 157 | params: 158 | - name: serviceAccount 159 | value: default 160 | templateRef: 161 | kind: ClusterTemplate 162 | name: config-writer-deliverable-template 163 | 164 | selector: 165 | apps.tanzu.vmware.com/has-tests: "true" 166 | apps.tanzu.vmware.com/workload-type: web 167 | workload-intent: code-analysis -------------------------------------------------------------------------------- /multi-language-support-with-sonar/supplychain/source-tester/run-template.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | 3 | --- 4 | apiVersion: carto.run/v1alpha1 5 | kind: ClusterRunTemplate 6 | metadata: 7 | name: tekton-source-pipelinerun 8 | spec: 9 | outputs: 10 | url: spec.params[?(@.name=="source-url")].value 11 | revision: spec.params[?(@.name=="source-revision")].value 12 | 13 | template: 14 | apiVersion: tekton.dev/v1beta1 15 | kind: PipelineRun 16 | metadata: 17 | generateName: $(runnable.metadata.name)$- 18 | labels: $(runnable.metadata.labels)$ 19 | spec: 20 | workspaces: 21 | - name: custom-maven-settings 22 | secret: 23 | secretName: maven-settings 24 | - name: maven-settings 25 | subPath: maven-repo-cache 26 | persistentVolumeClaim: 27 | claimName: supplychainpvc 28 | - name: supplychain-workspace 29 | emptyDir: {} 30 | pipelineRef: 31 | name: $(selected.metadata.name)$ 32 | params: 33 | - name: source-url 34 | value: $(runnable.spec.inputs.source-url)$ 35 | - name: source-revision 36 | value: $(runnable.spec.inputs.source-revision)$ 37 | -------------------------------------------------------------------------------- /multi-language-support-with-sonar/supplychain/source-tester/source-template.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | 3 | #@ if/end "testing-pipeline" not in data.values.excluded_templates: 4 | --- 5 | apiVersion: carto.run/v1alpha1 6 | kind: ClusterSourceTemplate 7 | metadata: 8 | name: testing-pipeline 9 | spec: 10 | urlPath: .status.outputs.url 11 | revisionPath: .status.outputs.revision 12 | 13 | healthRule: 14 | singleConditionType: Ready 15 | 16 | ytt: | 17 | #@ load("@ytt:data", "data") 18 | #@ load("@ytt:assert", "assert") 19 | 20 | #@ def merge_labels(fixed_values): 21 | #@ labels = {} 22 | #@ if hasattr(data.values.workload.metadata, "labels"): 23 | #@ labels.update(data.values.workload.metadata.labels) 24 | #@ end 25 | #@ labels.update(fixed_values) 26 | #@ return labels 27 | #@ end 28 | 29 | --- 30 | apiVersion: carto.run/v1alpha1 31 | kind: Runnable 32 | metadata: 33 | name: #@ data.values.workload.metadata.name 34 | labels: #@ merge_labels({ "app.kubernetes.io/component": "test" }) 35 | spec: 36 | #@ if/end hasattr(data.values.workload.spec, "serviceAccountName"): 37 | serviceAccountName: #@ data.values.workload.spec.serviceAccountName 38 | 39 | runTemplateRef: 40 | name: tekton-source-pipelinerun 41 | kind: ClusterRunTemplate 42 | 43 | selector: 44 | resource: 45 | apiVersion: tekton.dev/v1beta1 46 | kind: Pipeline 47 | matchingLabels: 48 | apps.tanzu.vmware.com/pipeline: test 49 | apps.tanzu.vmware.com/language: #@ data.values.workload.metadata.labels["apps.tanzu.vmware.com/language"] or assert.fail("please add a language label on your workload, e.g. apps.tanzu.vmware.com/language: java") 50 | inputs: 51 | source-url: #@ data.values.source.url 52 | source-revision: #@ data.values.source.revision -------------------------------------------------------------------------------- /shared/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/x95castle1/custom-cartographer-supply-chain-examples/6f0778ce94efc310684215e82308c34d8cb2e127/shared/.DS_Store -------------------------------------------------------------------------------- /shared/delivery/deploy/deployment.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: carto.run/v1alpha1 3 | kind: ClusterDeploymentTemplate 4 | metadata: 5 | name: app-deploy-tpl 6 | spec: 7 | observedCompletion: 8 | succeeded: 9 | key: '.status.conditions[?(@.type=="ReconcileSucceeded")].status' 10 | value: 'True' 11 | failed: 12 | key: '.status.conditions[?(@.type=="ReconcileSucceeded")].status' 13 | value: 'False' 14 | 15 | template: 16 | apiVersion: kappctrl.k14s.io/v1alpha1 17 | kind: App 18 | metadata: 19 | name: $(deliverable.metadata.name)$ 20 | spec: 21 | serviceAccountName: $(deliverable.spec.serviceAccountName)$ 22 | fetch: 23 | - http: 24 | url: $(deployment.url)$ 25 | template: 26 | - ytt: {} 27 | - kbld: {} 28 | deploy: 29 | - kapp: {} 30 | -------------------------------------------------------------------------------- /shared/git-secret.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | 3 | --- 4 | apiVersion: v1 5 | kind: Secret 6 | metadata: 7 | name: gitops-ssh-secret 8 | data: 9 | identity: #@ data.values.git_writer.base64_encoded_ssh_key 10 | known_hosts: #@ data.values.git_writer.base64_encoded_known_hosts -------------------------------------------------------------------------------- /shared/registry-secret.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | #@ load("@ytt:json", "json") 3 | --- 4 | apiVersion: v1 5 | kind: Secret 6 | metadata: 7 | name: tanzu-reg-cred 8 | type: kubernetes.io/dockerconfigjson 9 | stringData: 10 | #@ registry_creds = {"username": data.values.tanzu_registry.username, "password": data.values.tanzu_registry.password} 11 | .dockerconfigjson: #@ json.encode({"auths": {data.values.tanzu_registry.server: registry_creds}}) -------------------------------------------------------------------------------- /shared/secret.yml: -------------------------------------------------------------------------------- 1 | #@ load("@ytt:data", "data") 2 | #@ load("@ytt:json", "json") 3 | --- 4 | apiVersion: v1 5 | kind: Secret 6 | metadata: 7 | name: reg-cred 8 | type: kubernetes.io/dockerconfigjson 9 | stringData: 10 | #@ registry_creds = {"username": data.values.registry.username, "password": data.values.registry.password} 11 | .dockerconfigjson: #@ json.encode({"auths": {data.values.registry.server: registry_creds}}) -------------------------------------------------------------------------------- /shared/service-account.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 VMware 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | #@ load("@ytt:data", "data") 16 | 17 | # 18 | # The service-account is referenced by the workload and provides permissions for 19 | # Cartographer to create templated objects 20 | # 21 | --- 22 | apiVersion: v1 23 | kind: ServiceAccount 24 | metadata: 25 | name: #@ data.values.service_account_name 26 | #@ if data.values.registry.password != "": 27 | secrets: 28 | - name: reg-cred 29 | - name: tanzu-reg-cred 30 | imagePullSecrets: 31 | - name: reg-cred 32 | - name: tanzu-reg-cred 33 | #@ end 34 | --- 35 | apiVersion: rbac.authorization.k8s.io/v1 36 | kind: RoleBinding 37 | metadata: 38 | name: workload-role-binding 39 | roleRef: 40 | apiGroup: rbac.authorization.k8s.io 41 | kind: Role 42 | name: workload-role 43 | subjects: 44 | - kind: ServiceAccount 45 | name: #@ data.values.service_account_name 46 | 47 | --- 48 | apiVersion: rbac.authorization.k8s.io/v1 49 | kind: Role 50 | metadata: 51 | name: workload-role 52 | rules: 53 | - apiGroups: 54 | - source.toolkit.fluxcd.io 55 | - source.apps.tanzu.vmware.com 56 | - kpack.io 57 | - kapp.k14s.io/v1alpha1 58 | - kappctrl.k14s.io 59 | resources: 60 | - gitrepositories 61 | - imagerepositories 62 | - images 63 | - configs 64 | - apps 65 | verbs: 66 | - list 67 | - create 68 | - update 69 | - delete 70 | - patch 71 | - watch 72 | - get 73 | - apiGroups: 74 | - extensions 75 | - apps 76 | resources: 77 | - deployments 78 | verbs: 79 | - '*' 80 | - apiGroups: 81 | - tekton.dev 82 | resources: 83 | - tasks 84 | - taskruns 85 | - pipelineruns 86 | verbs: 87 | - '*' 88 | - apiGroups: 89 | - '' 90 | resources: 91 | - configmaps 92 | - pods 93 | verbs: 94 | - '*' 95 | - apiGroups: 96 | - carto.run 97 | resources: 98 | - runnables 99 | - deliverables 100 | verbs: 101 | - '*' 102 | - apiGroups: 103 | - scanning.apps.tanzu.vmware.com 104 | resources: 105 | - imagescans 106 | - sourcescans 107 | verbs: 108 | - '*' 109 | -------------------------------------------------------------------------------- /shared/supply-chain/deploy/k8s/app-deploy.yml: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | apiVersion: carto.run/v1alpha1 4 | kind: ClusterTemplate 5 | metadata: 6 | name: app-deploy 7 | spec: 8 | template: 9 | apiVersion: apps/v1 10 | kind: Deployment 11 | metadata: 12 | name: $(workload.metadata.name)$ 13 | spec: 14 | serviceAccountName: $(workload.spec.serviceAccountName)$ 15 | selector: 16 | matchLabels: 17 | app: $(workload.metadata.name)$ 18 | template: 19 | metadata: 20 | labels: 21 | app: $(workload.metadata.name)$ 22 | spec: 23 | containers: 24 | - name: main 25 | image: $(images.image.image)$ # consume the image that we depend 26 | # on from `kpack/Image` --------------------------------------------------------------------------------