-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add subdirectories (actions and Go code) documentation
- Loading branch information
Showing
10 changed files
with
374 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,148 @@ | ||
<div align="center"> | ||
<h1>Romeo</h1> | ||
<p>O Romeo, Romeo, whatfore art coverages Romeo?</p> | ||
<a href="https://pkg.go.dev/github.com/ctfer-io/romeo"><img src="https://shields.io/badge/-reference-blue?logo=go&style=for-the-badge" alt="reference"></a> | ||
<a href=""><img src="https://img.shields.io/github/license/ctfer-io/romeo?style=for-the-badge" alt="License"></a> | ||
<a href="https://coveralls.io/github/ctfer-io/romeo?branch=main"><img src="https://img.shields.io/coverallsCoverage/github/ctfer-io/romeo?style=for-the-badge" alt="Coverage Status"></a> | ||
<br> | ||
<a href="https://github.com/ctfer-io/romeo/actions/workflows/codeql-analysis.yaml"><img src="https://img.shields.io/github/actions/workflow/status/ctfer-io/romeo/codeql-analysis.yaml?style=for-the-badge&label=CodeQL" alt="CodeQL"></a> | ||
<a href="https://securityscorecards.dev/viewer/?uri=github.com/ctfer-io/romeo"><img src="https://img.shields.io/ossf-scorecard/github.com/ctfer-io/romeo?label=openssf%20scorecard&style=for-the-badge" alt="OpenSSF Scoreboard"></a> | ||
<img src="https://img.shields.io/badge/slsa-level%203-green?style=for-the-badge" alt="SLSA Level 3"> | ||
</div> | ||
|
||
The repository is structured as: | ||
- [webserver](webserver/) contains the Romeo Go webserver made for distant coverages fetch | ||
- [deploy](deploy/) contains the Go Pulumi deployment code for Romeo, in a Kubernetes environment | ||
- [action](action/) contains the TypeStript Pulumi bridge for GitHub Actions | ||
- [install](install/) contains the Kubernetes environment to deploy Romeo on Demand | ||
## How it works | ||
|
||
Romeo creates ephemeral environments on a Kubernetes cluster to measure Go binaries coverage. | ||
This work based on [this blog post](https://go.dev/blog/integration-test-coverage), so require **Go >= 1.20**. | ||
|
||
<div align="center"> | ||
<img src="res/workflow.excalidraw.png" alt="The Romeo workflow"> | ||
<img src="res/workflow.excalidraw.png" alt="The Romeo workflow" height="600px"> | ||
</div> | ||
|
||
The repository is structured as follows: | ||
1. [Webserver](webserver) is a Go server exposing an API that remotly executes the Go coverage merge. | ||
2. The resulting coverage data are later fetched by the [download Action](download). | ||
3. To deploy this you firstly instanciate a [deployment](deployment). | ||
4. To avoid passing a privileged account you can restrein the RBAC accesses with a pre-deployment [install](install). | ||
|
||
## Usage | ||
|
||
The recommended process is to run both [install](install) and [deployment](deployment) in a workflow. | ||
This provides good isolation thus ensure actual Go coverages. | ||
|
||
It is acceptable, mostly for performance reasons, to pre-[install](install) Romeo RBAC resources thus only running a [deployment] per workflow. | ||
Refer to their own documentation to implement this in your process. | ||
|
||
Configure secrets and inputs accordingly to each action/step documentation. | ||
|
||
```yaml | ||
name: Run Go tests | ||
|
||
on: [push] | ||
|
||
jobs: | ||
test: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
|
||
- name: Setup Go | ||
uses: actions/setup-go@v5 | ||
with: | ||
go-version-file: 'go.mod' | ||
|
||
- uses: pulumi/actions@v6 | ||
|
||
- name: Cache Go modules | ||
uses: actions/cache@v4 | ||
with: | ||
path: | | ||
~/.cache/go-build | ||
~/go/pkg/mod | ||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} | ||
restore-keys: | | ||
${{ runner.os }}-go- | ||
# ... Run your Go unit tests ... | ||
|
||
# Login local by default, you can login somewhere else. Adapt to your needs. | ||
- name: Pulumi login | ||
run: | | ||
pulumi login --local | ||
- name: Romeo install | ||
id: install | ||
uses: ctfer-io/romeo/install@v1 | ||
with: | ||
kubeconfig: ${{ secrets.KUBECONFIG }} | ||
api-server: ${{ secrets.API_SERVER }} | ||
|
||
- name: Romeo environment | ||
id: env | ||
uses: ctfer-io/romeo/environment@v1 | ||
with: | ||
kubeconfig: ${{ steps.install.outputs.kubeconfig }} | ||
namespace: ${{ steps.install.outputs.namespace }} | ||
|
||
- name: Run functional tests | ||
run: | | ||
go test ./... -run=^Test_F_ -json | tee -a gotest.json | ||
env: | ||
# Use a ServiceAccount with enough privileges to deploy the resources you require. | ||
# If not possible, you can use an administration account. | ||
KUBECONFIG: ${{ secrets.KUBECONFIG }} | ||
CLAIM_NAME: ${{ steps.env.outputs.claim-name }} | ||
NAMESPACE: ${{ steps.env.outputs.namespace }} | ||
# Put additional configuration if necessary... | ||
|
||
- name: Download coverages | ||
id: download | ||
uses: ctfer-io/romeo/download@v1 | ||
with: | ||
server: ${{ secrets.SERVER_BASE }}:${{ steps.env.outputs.port }} | ||
|
||
- name: Merge coverages | ||
run: | | ||
go tool covdata textfmt -i="${{ steps.download.outputs.directory }}" -o cov.out | ||
- name: Upload coverage to Coveralls | ||
uses: shogo82148/actions-goveralls@v1 | ||
with: | ||
path-to-profile: cov.out | ||
``` | ||
## Security | ||
### Signature and Attestations | ||
For deployment purposes (and especially in the deployment case of Kubernetes), you may want to ensure the integrity of what you run. | ||
The release assets are SLSA 3 and can be verified using [slsa-verifier](https://github.com/slsa-framework/slsa-verifier) using the following. | ||
```bash | ||
slsa-verifier verify-artifact "<path/to/release_artifact>" \ | ||
--provenance-path "<path/to/release_intoto_attestation>" \ | ||
--source-uri "github.com/ctfer-io/romeo" \ | ||
--source-tag "<tag>" | ||
``` | ||
|
||
The Docker image is SLSA 3 and can be verified using [slsa-verifier](https://github.com/slsa-framework/slsa-verifier) using the following. | ||
|
||
```bash | ||
slsa-verifier slsa-verifier verify-image "ctferio/romeo:<tag>@sha256:<digest>" \ | ||
--source-uri "github.com/ctfer-io/romeo" \ | ||
--source-tag "<tag>" | ||
``` | ||
|
||
Alternatives exist, like [Kyverno](https://kyverno.io/) for a Kubernetes-based deployment. | ||
|
||
### SBOMs | ||
|
||
A SBOM for the whole repository is generated on each release and can be found in the assets of it. | ||
They are signed as SLSA 3 assets. Refer to [Signature and Attestations](#signature-and-attestations) to verify their integrity. | ||
|
||
A SBOM is generated for the Docker image in its manifest, and can be inspected using the following. | ||
|
||
```bash | ||
docker buildx imagetools inspect "ctferio/romeo:<tag>" \ | ||
--format "{{ json .SBOM.SPDX }}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# Romeo download | ||
|
||
Download a [Romeo environment](../environment)'s coverages from an Action. | ||
|
||
It reaches the [Romeo webserver](../webserver) to archive and ship the coverages it reads from the shared volume of the Romeo environment, given the following architecture. | ||
|
||
<div align="center"> | ||
<img src="architecture.excalidraw.png" alt="Romeo download coverages" width="600px"> | ||
</div> | ||
|
||
## Usage | ||
|
||
### GitHub Actions | ||
|
||
To download coverages from a Romeo environment, use `ctfer-io/romeo/download`. | ||
|
||
```yaml | ||
- name: Download coverages | ||
id: download | ||
uses: ctfer-io/romeo/download@v1 | ||
with: | ||
server: ${{ secrets.SERVER_BASE }}:${{ steps.env.outputs.port }} | ||
``` | ||
#### Inputs | ||
| Name | Type | Default | Description | | ||
|---|---|---|---| | ||
| `server` | String | | Server URL to reach out the Romeo environment. | | ||
| `directory` | String | `coverout` | Directory to export the coverages data. | | ||
|
||
#### Outputs | ||
|
||
| Name | Type | Description | | ||
|---|---|---| | ||
| `directory` | String | Directory the coverages data were exported to. | | ||
|
||
### Manually | ||
|
||
The download action is a thin helper around the [Romeo webserver](../webserver) API: you can totally do it by hand. | ||
You need to reach the API at `/coverout` (`GET` method), then decode base 64 and unzip the result to the filesystem. | ||
|
||
```bash | ||
# From the Romeo environment directory | ||
curl "$SERVER_BASE:$(pulumi stack output -j | jq -r '.port')/coverout" | jq -r '.merged' | base64 -d > cov.zip | ||
unzip cov.zip && rm cov.zip | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# Romeo environment | ||
|
||
Deploy a Romeo environment from an Action, or manually. | ||
|
||
It deploys Kubernetes resources required to extract the Go coverages of binaries under tests/IVV, given the following architecture. | ||
|
||
<div align="center"> | ||
<img src="architecture.excalidraw.png" alt="Romeo environment Kubernetes architecture" width="600px"> | ||
</div> | ||
|
||
## Usage | ||
|
||
### GitHub Actions | ||
|
||
To deploy a Romeo environment from an Action, use `ctfer-io/romeo/environment`. | ||
It will create the Kubernetes resources. We recommend you deploy a [Romeo install](../install) per workflow run. | ||
|
||
```yaml | ||
- name: Romeo environment | ||
id: env | ||
uses: ctfer-io/romeo/environment@v1 | ||
with: | ||
kubeconfig: ${{ steps.install.outputs.kubeconfig }} | ||
namespace: ${{ steps.install.outputs.namespace }} | ||
``` | ||
Once your tests ran, you can [download the coverages](../download). | ||
At the end of the Action, it will delete the deployed resources. | ||
#### Inputs | ||
| Name | Type | Default | Description | | ||
|---|---|---|---| | ||
| `kubeconfig` | String | | **Required.** The kubeconfig to use for deploying a Romeo environment. | | ||
| `namespace` | String | | The namespace in which to deploy, in case the kubeconfig has access to many. | | ||
| `tag` | String | `latest` | **Required.** The [Romeo webserver docker tag](https://hub.docker.com/r/ctferio/romeo/tags) to use. | | ||
| `claim-name` | String | | If specified, turns on Romeo's coverage export in the given PersistenVolumeClaim name. This should only be used by CTFer.io to test Romeo itself. | | ||
|
||
#### Outputs | ||
|
||
| Name | Type | Description | | ||
|---|---|---| | ||
| `port` | String | The port to reach out the Romeo webserver. | | ||
| `claim-name` | String | The PersistentVolumeClaim name for binaries to mount in order to write coverage data. | | ||
| `namespace` | String | The namespace in which Romeo has been deployed. Reuse it to target the PersistentVolumeClaim corresponding to the claim-name. | | ||
|
||
### Manually | ||
|
||
You may want to deploy the "Romeo environment" to test things manually, or from a non-supported CI system (e.g. GitLab, Drone, Travis). | ||
|
||
It has the advantage of not requiring an extensive install of Romeo. We still recommend you **run one Romeo environment per workflow run** to ensure proper isolation between multiple runs thus avoid falsing your coverage measurements. | ||
|
||
```bash | ||
# Get in deploy directory | ||
cd deploy | ||
# Create stack and configure | ||
export PULUMI_CONFIG_PASSPHRASE="some-secret" | ||
pulumi stack init --secrets-provider passphrase --stack dev | ||
pulumi config set --secret kubeconfig "$(cat ~/.kube/config)" | ||
pulumi config set namespace "" | ||
# Deploy | ||
pulumi up -y | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# Romeo Install | ||
|
||
Install Romeo from an Action, or manually. | ||
|
||
It deploys RBAC resources given the following architecture, according to the needs of a [Romeo environment](../environment). | ||
|
||
<div align="center"> | ||
<img src="architecture.excalidraw.png" alt="Romeo install Kubernetes architecture" width="600px"> | ||
</div> | ||
|
||
## Usage | ||
|
||
### GitHub Actions | ||
|
||
To deploy a Romeo install from an Action, use `ctfer-io/romeo/install`. | ||
It will create the RBAC resources required by [Romeo environment](../environment) to deploy. | ||
|
||
```yaml | ||
- name: Romeo install | ||
id: install | ||
uses: ctfer-io/romeo/install@v1 | ||
with: | ||
kubeconfig: ${{ secrets.KUBECONFIG }} | ||
api-server: ${{ secrets.API_SERVER }} | ||
``` | ||
At the end of the Action, it will delete the deployed resources. | ||
#### Inputs | ||
| Name | Type | Default | Description | | ||
|---|---|---|---| | ||
| `kubeconfig` | String | | **Required.** The kubeconfig to use for installing Romeo and generating its own kubeconfig (with restreined privileges). | | ||
| `namespace` | String | | The namespace to install Romeo into. May be randomly generated, as long as it fits Kubernetes naming specification. If not specified, will be randomly generated. | | ||
| `api-server` | String | | **Required.** The Kubernetes api-server URL to pipe into the generated kubeconfig. Example: `https://cp.my-k8s.lan:6443`. | | ||
|
||
#### Outputs | ||
|
||
| Name | Type | Description | | ||
|---|---|---| | ||
| `kubeconfig` | String | The kubeconfig to use for deploying a Romeo environment. | | ||
| `namespace` | String | The namespace in which the install has took place. Pass it to Romeo's environment step and tests/IVV ones to know where to deploy too. | | ||
|
||
--- | ||
|
||
### Manually | ||
|
||
You may want to deploy the "Romeo install" once for your whole cluster, so _manually_. | ||
|
||
It has the advantage of making it only once, then share its instance between all repositories/CI under tests/IVV. | ||
Nevertheless, sharing is not always caring: collisions can happen, and we encourage you to deploy it once per CI run, or once at least once per repository. This enables you to update seemlessly between repositories rather than having to sync multiple people. | ||
|
||
```bash | ||
# Get in deploy directory | ||
cd deploy | ||
# Create stack and configure | ||
export PULUMI_CONFIG_PASSPHRASE="some-secret" | ||
pulumi stack init --secrets-provider passphrase --stack dev | ||
pulumi config set --secret kubeconfig "$(cat ~/.kube/config)" | ||
pulumi config set namespace "" | ||
pulumi config set api-server "https://cp.my-k8s.lan:6443" | ||
# Deploy | ||
pulumi up -y | ||
# Fetch ServiceAccount kubeconfig from outputs | ||
pulumi stack output --show-secrets -j | jq -r '.kubeconfig' > kubeconfig | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.