Skip to content

Commit 283cd65

Browse files
committed
Merge branch 'main' of https://github.com/stackabletech/ci
2 parents 014af40 + b86e9c1 commit 283cd65

File tree

11 files changed

+461
-213
lines changed

11 files changed

+461
-213
lines changed

tools/harbor_sbom_browser/Cargo.lock

Lines changed: 335 additions & 109 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tools/harbor_sbom_browser/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ edition = "2021"
88
[dependencies]
99
axum = "0.7.4"
1010
axum-extra = { version = "0.9.2", features = ["erased-json"] }
11-
base64 = "0.21.7"
11+
base64 = "0.22.0"
1212
futures = "0.3.30"
1313
lazy_static = "1.4.0"
1414
regex = "1.10.3"

tools/harbor_sbom_browser/src/handlers/artifact_tree.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ lazy_static! {
4949
pub async fn render_as_html(
5050
State(cached_rendered_artifact_tree): State<CachedObject<Html<String>>>,
5151
) -> Result<Html<String>, ArtifactTreeError> {
52-
5352
// if the artifact tree is already cached, return it
5453
if let Some(html) = cached_rendered_artifact_tree.get() {
5554
return Ok(html);

tools/harbor_sbom_browser/src/handlers/sbom.rs

Lines changed: 3 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,15 @@
1-
use crate::structs::{Dsse, InTotoAttestation};
21
use axum::{
32
extract::Path,
4-
http::{header, HeaderMap, StatusCode},
5-
response::{IntoResponse, Response},
3+
http::{header, HeaderMap},
64
};
75
use axum_extra::response::ErasedJson;
8-
use base64::prelude::*;
9-
use lazy_static::lazy_static;
10-
use regex::Regex;
11-
use snafu::{ResultExt, Snafu};
12-
use std::process::Command;
13-
use strum::{EnumDiscriminants, IntoStaticStr};
14-
use tracing::error;
156

16-
lazy_static! {
17-
static ref SHA256_REGEX: Regex = Regex::new(r"^[a-f0-9]{64}$").unwrap();
18-
static ref ALPHANUMERIC_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9\-]+$").unwrap();
19-
}
20-
21-
#[derive(Snafu, Debug, EnumDiscriminants)]
22-
#[strum_discriminants(derive(IntoStaticStr))]
23-
#[snafu(visibility(pub))]
24-
#[allow(clippy::enum_variant_names)]
25-
pub enum DownloadSbomError {
26-
#[snafu(display("invalid repository or digest"))]
27-
InvalidSbomParameters,
28-
#[snafu(display("failed to verify SBOM"))]
29-
SbomVerification {
30-
cosign_stdout: String,
31-
cosign_stderr: String,
32-
cosign_status: std::process::ExitStatus,
33-
},
34-
#[snafu(display("cannot parse DSSE"))]
35-
ParseDsse { source: serde_json::Error },
36-
#[snafu(display("cannot decode DSSE payload"))]
37-
DecodeDssePayload { source: base64::DecodeError },
38-
#[snafu(display("cannot parse DSSE payload as string"))]
39-
ParseDssePayloadAsString { source: std::str::Utf8Error },
40-
#[snafu(display("cannot parse in-toto attestation"))]
41-
ParseInTotoAttestation { source: serde_json::Error },
42-
#[snafu(display("failed to execute cosign"))]
43-
CosignExecution { source: std::io::Error },
44-
}
45-
46-
impl IntoResponse for DownloadSbomError {
47-
fn into_response(self) -> Response {
48-
error!("error: {:?}", self);
49-
(
50-
StatusCode::INTERNAL_SERVER_ERROR,
51-
format!("Something went wrong: {}", self),
52-
)
53-
.into_response()
54-
}
55-
}
7+
use crate::utils::{verify_attestation, DownloadSbomError};
568

579
pub async fn download(
5810
Path((repository, digest)): Path<(String, String)>,
5911
) -> Result<(HeaderMap, ErasedJson), DownloadSbomError> {
60-
if !SHA256_REGEX.is_match(&digest) || !ALPHANUMERIC_REGEX.is_match(&repository) {
61-
return Err(DownloadSbomError::InvalidSbomParameters);
62-
}
63-
let cmd_output = Command::new("cosign")
64-
.arg("verify-attestation")
65-
.arg("--type")
66-
.arg("cyclonedx")
67-
.arg("--certificate-identity-regexp")
68-
.arg("^https://github.com/stackabletech/.+/.github/workflows/.+@.+")
69-
.arg("--certificate-oidc-issuer")
70-
.arg("https://token.actions.githubusercontent.com")
71-
.arg(format!(
72-
"oci.stackable.tech/sdp/{}@sha256:{}",
73-
repository, digest
74-
))
75-
.output()
76-
.context(CosignExecutionSnafu)?;
77-
78-
let output = String::from_utf8_lossy(&cmd_output.stdout);
79-
if !cmd_output.status.success() {
80-
let stderr_output = String::from_utf8_lossy(&cmd_output.stderr);
81-
return Err(DownloadSbomError::SbomVerification {
82-
cosign_stdout: output.to_string(),
83-
cosign_stderr: stderr_output.to_string(),
84-
cosign_status: cmd_output.status,
85-
});
86-
}
87-
88-
let dsse = serde_json::from_str::<Dsse>(&output).context(ParseDsseSnafu)?;
89-
let attestation_bytes = BASE64_STANDARD
90-
.decode(dsse.payload)
91-
.context(DecodeDssePayloadSnafu)?;
92-
let attestation_string =
93-
std::str::from_utf8(&attestation_bytes).context(ParseDssePayloadAsStringSnafu)?;
94-
let attestation = serde_json::from_str::<InTotoAttestation>(attestation_string)
95-
.context(ParseInTotoAttestationSnafu)?;
12+
let attestation = verify_attestation(&repository, &digest).await?;
9613
let mut headers = HeaderMap::new();
9714
headers.insert(header::CONTENT_TYPE, "application/json".parse().unwrap());
9815
headers.insert(

tools/harbor_sbom_browser/src/main.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use structs::CachedObject;
33

44
pub mod handlers;
55
pub mod structs;
6+
mod utils;
7+
68
use crate::handlers::*;
79

810
#[tokio::main]
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use crate::structs::{Dsse, InTotoAttestation};
2+
use axum::http::StatusCode;
3+
use axum::response::{IntoResponse, Response};
4+
use base64::prelude::BASE64_STANDARD;
5+
use base64::Engine;
6+
use lazy_static::lazy_static;
7+
use regex::Regex;
8+
use snafu::ResultExt;
9+
use snafu::Snafu;
10+
use std::process::Command;
11+
use strum::{EnumDiscriminants, IntoStaticStr};
12+
use tracing::error;
13+
14+
lazy_static! {
15+
static ref SHA256_REGEX: Regex = Regex::new(r"^[a-f0-9]{64}$").unwrap();
16+
static ref ALPHANUMERIC_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9\-]+$").unwrap();
17+
}
18+
19+
#[derive(Snafu, Debug, EnumDiscriminants)]
20+
#[strum_discriminants(derive(IntoStaticStr))]
21+
#[snafu(visibility(pub))]
22+
#[allow(clippy::enum_variant_names)]
23+
pub enum DownloadSbomError {
24+
#[snafu(display("invalid repository or digest"))]
25+
InvalidSbomParameters,
26+
#[snafu(display("failed to verify SBOM"))]
27+
SbomVerification {
28+
cosign_stdout: String,
29+
cosign_stderr: String,
30+
cosign_status: std::process::ExitStatus,
31+
},
32+
#[snafu(display("cannot parse DSSE"))]
33+
ParseDsse { source: serde_json::Error },
34+
#[snafu(display("cannot decode DSSE payload"))]
35+
DecodeDssePayload { source: base64::DecodeError },
36+
#[snafu(display("cannot parse DSSE payload as string"))]
37+
ParseDssePayloadAsString { source: std::str::Utf8Error },
38+
#[snafu(display("cannot parse in-toto attestation"))]
39+
ParseInTotoAttestation { source: serde_json::Error },
40+
#[snafu(display("failed to execute cosign"))]
41+
CosignExecution { source: std::io::Error },
42+
}
43+
44+
impl IntoResponse for DownloadSbomError {
45+
fn into_response(self) -> Response {
46+
error!("error: {:?}", self);
47+
(
48+
StatusCode::INTERNAL_SERVER_ERROR,
49+
format!("Something went wrong: {}", self),
50+
)
51+
.into_response()
52+
}
53+
}
54+
55+
pub async fn verify_attestation(
56+
repository: &str,
57+
digest: &str,
58+
) -> Result<InTotoAttestation, DownloadSbomError> {
59+
if !SHA256_REGEX.is_match(digest) || !ALPHANUMERIC_REGEX.is_match(repository) {
60+
return Err(DownloadSbomError::InvalidSbomParameters);
61+
}
62+
let cmd_output = Command::new("cosign")
63+
.arg("verify-attestation")
64+
.arg("--type")
65+
.arg("cyclonedx")
66+
.arg("--certificate-identity-regexp")
67+
.arg("^https://github.com/stackabletech/.+/.github/workflows/.+@.+")
68+
.arg("--certificate-oidc-issuer")
69+
.arg("https://token.actions.githubusercontent.com")
70+
.arg(format!(
71+
"oci.stackable.tech/sdp/{}@sha256:{}",
72+
repository, digest
73+
))
74+
.output()
75+
.context(CosignExecutionSnafu)?;
76+
77+
if !cmd_output.status.success() {
78+
let stderr_output = String::from_utf8_lossy(&cmd_output.stderr);
79+
return Err(DownloadSbomError::SbomVerification {
80+
cosign_stdout: String::from_utf8_lossy(&cmd_output.stdout).to_string(),
81+
cosign_stderr: stderr_output.to_string(),
82+
cosign_status: cmd_output.status,
83+
});
84+
}
85+
86+
let output = String::from_utf8_lossy(&cmd_output.stdout);
87+
let dsse = serde_json::from_str::<Dsse>(&output).context(ParseDsseSnafu)?;
88+
let attestation_bytes = BASE64_STANDARD
89+
.decode(dsse.payload)
90+
.context(DecodeDssePayloadSnafu)?;
91+
let attestation_string =
92+
std::str::from_utf8(&attestation_bytes).context(ParseDssePayloadAsStringSnafu)?;
93+
serde_json::from_str::<InTotoAttestation>(attestation_string)
94+
.context(ParseInTotoAttestationSnafu)
95+
}

tools/testing-toolbox/create_testsuite.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
platform_name = None
1010
k8s_version = None
1111
operator_version = None
12+
test_script_params = None
1213
git_branch = None
1314
beku_suite = None
1415
metadata_annotations = {}
@@ -85,12 +86,14 @@ def read_params():
8586
- GIT_BRANCH
8687
- BEKU_SUITE
8788
- OPERATOR_VERSION
89+
- TEST_SCRIPT_PARAMS
8890
- METADATA_ANNOTATION_xyz
8991
"""
9092
global testsuite_name
9193
global platform_name
9294
global k8s_version
9395
global operator_version
96+
global test_script_params
9497
global git_branch
9598
global beku_suite
9699
global metadata_annotations
@@ -107,6 +110,8 @@ def read_params():
107110
platform_name, k8s_version = read_platform_and_k8s_version()
108111
if 'OPERATOR_VERSION' in os.environ:
109112
operator_version = os.environ["OPERATOR_VERSION"]
113+
if 'TEST_SCRIPT_PARAMS' in os.environ:
114+
test_script_params = os.environ["TEST_SCRIPT_PARAMS"]
110115
if 'GIT_BRANCH' in os.environ:
111116
git_branch = os.environ["GIT_BRANCH"]
112117
if 'BEKU_SUITE' in os.environ:
@@ -219,6 +224,11 @@ def create_testsuite():
219224
cluster_definition['metadata']['annotations'] = {}
220225
for key,value in metadata_annotations.items():
221226
cluster_definition['metadata']['annotations'][key] = value
222-
223227
write_cluster_definition(cluster_definition)
224-
write_test_script(testsuite, testsuite_platform_definition['test_params'] if 'test_params' in testsuite_platform_definition else '')
228+
229+
test_script_params_array = []
230+
if 'test_params' in testsuite_platform_definition:
231+
test_script_params_array.append(testsuite_platform_definition['test_params'])
232+
if test_script_params:
233+
test_script_params_array.append(test_script_params)
234+
write_test_script(testsuite, ' '.join(test_script_params_array))

tools/testing-toolbox/jjb/custom_test_jobs.j2

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
export PLATFORM_ID=`echo $TEST_PLATFORM | cut -d '<' -f 2 | cut -d '|' -f 1`
6565
export K8S_VERSION=`echo $TEST_PLATFORM | cut -d '<' -f 2 | cut -d '|' -f 2 | cut -d '>' -f 1`
6666
export GIT_BRANCH=`echo $GIT_BRANCH_OR_TAG | sed s#origin/##g`
67+
export TEST_SCRIPT_PARAM_OPERATOR_NAME=`echo {{ testsuite.name }} | sed s#-operator##g`
6768

6869
# We're using Docker from within a Docker container, so we have to make sure to provide
6970
# the Docker daemon with the proper absolute path for volume mounts.
@@ -87,7 +88,8 @@
8788
--env K8S_VERSION=$K8S_VERSION \
8889
--env GIT_BRANCH=$GIT_BRANCH \
8990
--env BEKU_SUITE=$BEKU_SUITE \
90-
--env OPERATOR_VERSION=$OPERATOR_VERSION \
91+
--env OPERATOR_VERSION=NONE \
92+
--env TEST_SCRIPT_PARAMS="--operator ${TEST_SCRIPT_PARAM_OPERATOR_NAME}=${OPERATOR_VERSION}" \
9193
--env METADATA_ANNOTATION_t2.stackable.tech/jenkins-user="${BUILD_USER}" \
9294
--env METADATA_ANNOTATION_t2.stackable.tech/jenkins-user-id=${BUILD_USER_ID} \
9395
--env METADATA_ANNOTATION_t2.stackable.tech/jenkins-user-email=${BUILD_USER_EMAIL} \
@@ -127,7 +129,6 @@
127129
custom-message: |
128130
*platform:* $TEST_PLATFORM
129131
*branch or tag:* `$GIT_BRANCH_OR_TAG`
130-
*operator version:* `$OPERATOR_VERSION`
131132
(<$BUILD_URL|Open in classic Jenkins UI>)
132133
(<${BUILD_URL}artifact/testsuite/target/logs.html|Open logs overview>)
133134
- description-setter:

tools/testing-toolbox/jjb/nightly_test_jobs.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
--env PLATFORM='{{ testsuite.nightly_test.platform }}' \
6060
--env GIT_BRANCH=main \
6161
--env BEKU_SUITE=nightly \
62-
--env OPERATOR_VERSION=DEV \
62+
--env OPERATOR_VERSION=NONE \
6363
--env METADATA_ANNOTATION_t2.stackable.tech/jenkins-user="${BUILD_USER}" \
6464
--env METADATA_ANNOTATION_t2.stackable.tech/jenkins-user-id=${BUILD_USER_ID} \
6565
--env METADATA_ANNOTATION_t2.stackable.tech/jenkins-user-email=${BUILD_USER_EMAIL} \

tools/testing-toolbox/jjb/self_service_test_jobs.j2

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,6 @@
2020
choices:{% for platform in platforms[testsuite.name] %}
2121
- {{ platform.display_name }}, {{ platform.version }} <{{ platform.id }}|{{ platform.version }}>{% endfor %}
2222
description: On which platform should the test run?
23-
- extended-choice:
24-
name: OPERATOR_VERSION
25-
description: Version of the operator (binary) this test should use
26-
property-file: /var/jenkins_home/workspace/Available Versions/versions.properties
27-
property-key: {{ testsuite.name }}
28-
quote-value: false
29-
visible-items: 10
3023
- string:
3124
name: CLUSTER_NICKNAME
3225
description: Nickname of the cluster to be created (mandatory)
@@ -74,7 +67,7 @@
7467
--env TESTSUITE={{ testsuite.name }} \
7568
--env PLATFORM=$PLATFORM_ID \
7669
--env K8S_VERSION=$K8S_VERSION \
77-
--env OPERATOR_VERSION=$OPERATOR_VERSION \
70+
--env OPERATOR_VERSION=NONE \
7871
--env METADATA_ANNOTATION_t2.stackable.tech/jenkins-user="${BUILD_USER}" \
7972
--env METADATA_ANNOTATION_t2.stackable.tech/jenkins-user-id=${BUILD_USER_ID} \
8073
--env METADATA_ANNOTATION_t2.stackable.tech/jenkins-user-email=${BUILD_USER_EMAIL} \

0 commit comments

Comments
 (0)