use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Provider {
GitHubActions,
GitLabCI,
CircleCI,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Severity {
Error,
Warning,
Info,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Location {
pub line: usize,
pub column: usize,
pub job: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Issue {
pub severity: Severity,
pub message: String,
pub location: Option<Location>,
pub suggestion: Option<String>,
}
impl Issue {
pub fn for_job(
severity: Severity,
message: &str,
job_id: &str,
line: usize,
column: usize,
suggestion: Option<String>,
) -> Self {
Issue {
severity,
message: message.to_string(),
location: Some(Location {
line,
column,
job: Some(job_id.to_string()),
}),
suggestion,
}
}
pub fn new(severity: Severity, message: &str, suggestion: Option<String>) -> Self {
Issue {
severity,
message: message.to_string(),
location: None,
suggestion,
}
}
}
impl Pipeline {
pub fn find_line(&self, key: &str) -> (usize, usize) {
for (idx, line) in self.source.lines().enumerate() {
let trimmed = line.trim_start();
if trimmed.starts_with(key) {
let column = line.len() - trimmed.len() + 1;
return (idx + 1, column);
}
}
(0, 0)
}
pub fn find_job_line(&self, job_id: &str, key_hint: &str) -> (usize, usize) {
for (idx, line) in self.source.lines().enumerate() {
let trimmed = line.trim();
let prefix = format!("{}:", job_id);
if trimmed.starts_with(&prefix) {
let remainder = &trimmed[prefix.len()..];
if remainder.is_empty() || remainder.starts_with(char::is_whitespace) {
let column = line.len() - line.trim_start().len() + 1;
return (idx + 1, column);
}
}
if trimmed.starts_with(&format!("{}:", key_hint)) {
let column = line.len() - line.trim_start().len() + 1;
return (idx + 1, column);
}
}
(0, 0)
}
}
#[derive(Debug, Clone)]
pub struct AuditOptions {
pub check_docker_images: bool,
pub strict_mode: bool,
}
impl Default for AuditOptions {
fn default() -> Self {
Self {
check_docker_images: true,
strict_mode: false,
}
}
}
#[derive(Debug, Serialize)]
pub struct AuditResult {
pub provider: Provider,
pub issues: Vec<Issue>,
pub summary: String,
}
#[derive(Debug)]
pub struct Pipeline {
pub provider: Provider,
pub jobs: Vec<Job>,
pub env: Vec<EnvVar>,
pub source: String,
}
#[derive(Debug)]
pub struct Job {
pub id: String,
pub name: Option<String>,
pub depends_on: Vec<String>,
pub steps: Vec<Step>,
pub env: Vec<EnvVar>,
pub container_image: Option<String>,
pub service_images: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct Step {
pub name: Option<String>,
pub uses: Option<String>,
pub run: Option<String>,
pub env: Vec<EnvVar>,
pub with_inputs: Option<serde_yaml::Value>,
}
#[derive(Debug, Clone)]
pub struct EnvVar {
pub key: String,
pub value: String,
pub is_secret: bool,
}