Skip to content
This repository was archived by the owner on Jan 19, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ k8s-openapi = { version = "0.24.0", default-features = false, features = [
"v1_30",
] }
lazy_static = "1.4.0"
oci-spec = "0.7.1"
pem = "3"
policy-evaluator = { git = "https://github.com/kubewarden/policy-evaluator", tag = "v0.21.0" }
prettytable-rs = "^0.10"
Expand Down
21 changes: 21 additions & 0 deletions chart/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
apiVersion: v2
name: volumes-psp
description: Pod Security Policy that controls usage of volumes
type: application
home: https://github.com/kubewarden/volumes-psp-policy
keywords: null
version: '123'
appVersion: '123'
annotations:
io.artifacthub.displayName: Volumes PSP
io.artifacthub.keywords: psp, pod, volumes
io.artifacthub.resources: Pod
io.kubewarden.policy.author: Kubewarden developers <cncf-kubewarden-maintainers@lists.cncf.io>
io.kubewarden.policy.category: PSP
io.kubewarden.policy.description: Pod Security Policy that controls usage of volumes
io.kubewarden.policy.license: Apache-2.0
io.kubewarden.policy.ociUrl: ghcr.io/kubewarden/policies/volumes-psp
io.kubewarden.policy.severity: medium
io.kubewarden.policy.source: https://github.com/kubewarden/volumes-psp-policy
io.kubewarden.policy.title: volumes-psp
io.kubewarden.policy.url: https://github.com/kubewarden/volumes-psp-policy
23 changes: 23 additions & 0 deletions chart/questions.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
questions:
- default: null
description: >-
Replacement for the Kubernetes Pod Security Policy that controls the usage
of volumes in pods. The policy takes the list of the allowed volume types
using the allowedTypes setting. The special value * can be used to allow all
kind of volumes.
group: Settings
required: false
hide_input: true
type: string
variable: description
- default: []
description: ''
tooltip: >-
A list of the allowed volume types. Note: no other value can be specified
together with *. For example, allowedTypes: ['*', 'configMap'] is not a
valid configuration setting.
group: Settings
label: Allowed types
required: false
type: array[
variable: allowedTypes
20 changes: 20 additions & 0 deletions chart/templates/policy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
apiVersion: policies.kubewarden.io/v1
{{- if eq .Values.clusterScoped true }}
kind: ClusterAdmissionPolicy
{{- else }}
kind: AdmissionPolicy
{{- end }}
metadata:
name: {{ .Release.name }}
{{- if eq .Values.clusterScoped false }}
namespace: {{ .Release.namespace }}
{{- end }}
spec:
module: '{{ .Values.spec.module.repository }}:{{ .Values.spec.module.tag }}'
mode: {{ .Values.spec.mode }}
mutating: {{ .Values.spec.mutating }}
rules:
{{- toYaml .Values.spec.rules | nindent 4 }}
settings:
{{- toYaml .Values.spec.settings | replace "|\n" "" | nindent 2 }}
21 changes: 21 additions & 0 deletions chart/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
global:
cattle:
systemDefaultRegistry: ghcr.io
clusterScoped: true
spec:
module:
repository: kubewarden/policies/volumes-psp
tag: '123'
mode: kubewarden-wapc
mutating: false
contextAwareResources: []
rules:
- apiGroups:
- ''
apiVersions:
- v1
resources:
- pods
operations:
- CREATE
settings: {}
40 changes: 39 additions & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::path::PathBuf;

use clap::{
builder::PossibleValuesParser, crate_authors, crate_description, crate_name, crate_version,
Arg, ArgAction, ArgGroup, Command,
value_parser, Arg, ArgAction, ArgGroup, Command,
};
use lazy_static::lazy_static;

Expand Down Expand Up @@ -525,6 +527,39 @@ fn subcommand_scaffold() -> Command {
];
admission_request_args.sort_by(|a, b| a.get_id().cmp(b.get_id()));

let chart_args = vec![
Arg::new("version")
.long("version")
.short('t')
.required(true)
.value_name("STRING")
.help("The version of the policy"),
Arg::new("no-settings")
.long("no-settings")
.action(ArgAction::SetTrue)
.help("Disable settings for this policy"),
Arg::new("metadata-path")
.long("metadata-path")
.short('m')
.value_name("PATH")
.value_parser(value_parser!(PathBuf))
.default_value("metadata.yml")
.help("File containing the metadata of the policy"),
Arg::new("questions-path")
.long("questions-path")
.short('q')
.value_name("PATH")
.value_parser(value_parser!(PathBuf))
.help("File containing the questions-ui content of the policy"),
Arg::new("output-path")
.long("output-path")
.short('o')
.value_name("PATH")
.value_parser(value_parser!(PathBuf))
.default_value("chart")
.help("Path where the Helm chart will be stored"),
];

let mut subcommands = vec![
Command::new("verification-config")
.about("Output a default Sigstore verification configuration file"),
Expand All @@ -540,6 +575,9 @@ fn subcommand_scaffold() -> Command {
Command::new("admission-request")
.about("Scaffold an AdmissionRequest object")
.args(admission_request_args),
Command::new("chart")
.about("Output a Helm chart for a Kubewarden policy")
.args(chart_args)
];
subcommands.sort_by(|a, b| a.get_name().cmp(b.get_name()));

Expand Down
174 changes: 104 additions & 70 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,79 +312,113 @@
Ok(())
}
Some("scaffold") => {
if let Some(matches) = matches.subcommand_matches("scaffold") {
if let Some(_matches) = matches.subcommand_matches("verification-config") {
println!("{}", scaffold::verification_config()?);
}
}
if let Some(matches) = matches.subcommand_matches("scaffold") {
if let Some(artifacthub_matches) = matches.subcommand_matches("artifacthub") {
let metadata_file = artifacthub_matches
.get_one::<String>("metadata-path")
.map(|output| PathBuf::from_str(output).unwrap())
.unwrap();
let version = artifacthub_matches.get_one::<String>("version").unwrap();
let gh_release_tag = artifacthub_matches
.get_one::<String>("gh-release-tag")
.cloned();
let questions_file = artifacthub_matches
.get_one::<String>("questions-path")
.map(|output| PathBuf::from_str(output).unwrap());
let content = scaffold::artifacthub(
metadata_file,
version,
gh_release_tag.as_deref(),
questions_file,
)?;
if let Some(output) = artifacthub_matches.get_one::<String>("output") {
let output_path = PathBuf::from_str(output)?;
fs::write(output_path, content)?;
} else {
println!("{}", content);
if let Some(scaffold_matches) = matches.subcommand_matches("scaffold") {
match scaffold_matches.subcommand() {
Some(("verification-config", _)) => {
println!("{}", scaffold::verification_config()?);
}
Some(("artifacthub", artifacthub_matches)) => {
let metadata_file = artifacthub_matches
.get_one::<String>("metadata-path")
.map(|output| PathBuf::from_str(output).unwrap())
.unwrap();
let version = artifacthub_matches.get_one::<String>("version").unwrap();
let gh_release_tag = artifacthub_matches
.get_one::<String>("gh-release-tag")
.cloned();
let questions_file = artifacthub_matches
.get_one::<String>("questions-path")
.map(|output| PathBuf::from_str(output).unwrap());

Check warning on line 331 in src/main.rs

View check run for this annotation

Codecov / codecov/patch

src/main.rs#L321-L331

Added lines #L321 - L331 were not covered by tests
let content = scaffold::artifacthub(
metadata_file,
version,
gh_release_tag.as_deref(),
questions_file,
)?;

Check warning on line 337 in src/main.rs

View check run for this annotation

Codecov / codecov/patch

src/main.rs#L333-L337

Added lines #L333 - L337 were not covered by tests
if let Some(output) = artifacthub_matches.get_one::<String>("output") {
let output_path = PathBuf::from_str(output)?;
fs::write(output_path, content)?;
} else {
println!("{}", content);
}

Check warning on line 343 in src/main.rs

View check run for this annotation

Codecov / codecov/patch

src/main.rs#L342-L343

Added lines #L342 - L343 were not covered by tests
}
Some(("manifest", manifest_matches)) => {
scaffold_manifest_command(manifest_matches).await?;
}
Some(("vap", vap_matches)) => {
let cel_policy_uri = vap_matches.get_one::<String>("cel-policy").unwrap();
let vap_file: PathBuf =
vap_matches.get_one::<String>("policy").unwrap().into();
let vap_binding_file: PathBuf =
vap_matches.get_one::<String>("binding").unwrap().into();

scaffold::vap(
cel_policy_uri.as_str(),
vap_file.as_path(),
vap_binding_file.as_path(),
)?;
}
Some(("admission-request", admission_request_matches)) => {
let operation: scaffold::AdmissionRequestOperation =
admission_request_matches
.get_one::<String>("operation")
.unwrap()
.parse::<scaffold::AdmissionRequestOperation>()
.map_err(|e| anyhow!("Error parsing operation: {}", e))?;

Check warning on line 367 in src/main.rs

View check run for this annotation

Codecov / codecov/patch

src/main.rs#L364-L367

Added lines #L364 - L367 were not covered by tests
let object_path: Option<PathBuf> =
if admission_request_matches.contains_id("object") {
Some(
admission_request_matches
.get_one::<String>("object")
.unwrap()
.into(),
)

Check warning on line 375 in src/main.rs

View check run for this annotation

Codecov / codecov/patch

src/main.rs#L371-L375

Added lines #L371 - L375 were not covered by tests
} else {
None
};
let old_object_path: Option<PathBuf> =
if admission_request_matches.contains_id("old-object") {
Some(
admission_request_matches
.get_one::<String>("old-object")
.unwrap()
.into(),
)

Check warning on line 386 in src/main.rs

View check run for this annotation

Codecov / codecov/patch

src/main.rs#L382-L386

Added lines #L382 - L386 were not covered by tests
} else {
None
};

scaffold::admission_request(operation, object_path, old_object_path)
.await?;

Check warning on line 392 in src/main.rs

View check run for this annotation

Codecov / codecov/patch

src/main.rs#L392

Added line #L392 was not covered by tests
}
Some(("chart", chart_matches)) => {
let version = chart_matches
.get_one::<String>("version")
.expect("version is required");
let metadata_path = chart_matches
.get_one::<PathBuf>("metadata-path")
.expect("metadata path is required");
let has_settings = !chart_matches
.get_one::<bool>("no-settings")
.expect("no-settings is required")
.to_owned();
let questions_path = chart_matches.get_one::<PathBuf>("questions-path");

let output_path = chart_matches
.get_one::<PathBuf>("output-path")
.expect("output path is required");

scaffold::chart(
version,
has_settings,
metadata_path,
questions_path,
output_path,
)?;

Check warning on line 417 in src/main.rs

View check run for this annotation

Codecov / codecov/patch

src/main.rs#L395-L417

Added lines #L395 - L417 were not covered by tests
}
_ => {}
}
}
if let Some(matches) = matches.subcommand_matches("scaffold") {
if let Some(matches) = matches.subcommand_matches("manifest") {
scaffold_manifest_command(matches).await?;
};
}
if let Some(matches) = matches.subcommand_matches("scaffold") {
if let Some(matches) = matches.subcommand_matches("vap") {
let cel_policy_uri = matches.get_one::<String>("cel-policy").unwrap();
let vap_file: PathBuf = matches.get_one::<String>("policy").unwrap().into();
let vap_binding_file: PathBuf =
matches.get_one::<String>("binding").unwrap().into();

scaffold::vap(
cel_policy_uri.as_str(),
vap_file.as_path(),
vap_binding_file.as_path(),
)?;
};
}
if let Some(matches) = matches.subcommand_matches("scaffold") {
if let Some(matches) = matches.subcommand_matches("admission-request") {
let operation: scaffold::AdmissionRequestOperation = matches
.get_one::<String>("operation")
.unwrap()
.parse::<scaffold::AdmissionRequestOperation>()
.map_err(|e| anyhow!("Error parsing operation: {}", e))?;
let object_path: Option<PathBuf> = if matches.contains_id("object") {
Some(matches.get_one::<String>("object").unwrap().into())
} else {
None
};
let old_object_path: Option<PathBuf> = if matches.contains_id("old-object") {
Some(matches.get_one::<String>("old-object").unwrap().into())
} else {
None
};

scaffold::admission_request(operation, object_path, old_object_path).await?;
};
}

Ok(())
}
Some("completions") => {
Expand Down
3 changes: 3 additions & 0 deletions src/scaffold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ pub(crate) use artifacthub::artifacthub;
mod admission_request;
pub(crate) use admission_request::Operation as AdmissionRequestOperation;
pub(crate) use admission_request::{admission_request, DEFAULT_KWCTL_CACHE};

mod chart;
pub(crate) use chart::chart;
Loading
Loading