# CI/CD and Runner Security Assessment Pack

> **Intro:** These exercises are meant to feel like engineering assessment tasks for Product Security. The snippets are short, but each one hides a trust-boundary mistake.

## Task 1 - Jenkins pipeline reads secrets into shell and prints too much

```groovy
pipeline {
  agent any
  stages {
    stage('Deploy') {
      steps {
        withCredentials([string(credentialsId: 'prod-api-key', variable: 'API_KEY')]) {
          sh '''
            set -x
            curl -H "Authorization: Bearer $API_KEY" https://deploy.example.com/release
          '''
        }
      }
    }
  }
}
```

### Prompt

Find the weakness and propose a safer pattern.

<details>

<summary><strong>Reveal the worked answer</strong></summary>

#### Weakness

`set -x` can echo commands and potentially expose secrets in logs or downstream tooling. Even masked output handling is not something to trust blindly here.

#### Better pattern

* avoid debug echo around secret-bearing commands;
* keep logs minimal;
* prefer narrow-scope deploy identity and reviewed wrapper scripts.

```groovy
withCredentials([string(credentialsId: 'prod-api-key', variable: 'API_KEY')]) {
  sh '''
    set +x
    curl --fail -sS -H "Authorization: Bearer $API_KEY" https://deploy.example.com/release
  '''
}
```

</details>

## Task 2 - GitHub Actions workflow grants more token access than needed

```yaml
name: ci
on: [push, pull_request]
permissions: write-all
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test
```

### Prompt

What is wrong even if this workflow only runs tests?

<details>

<summary><strong>Reveal the worked answer</strong></summary>

#### Problem

`write-all` violates least privilege. If a third-party action or job step is compromised, the workflow token may modify repository state far beyond what the job requires.

#### Better version

```yaml
permissions:
  contents: read
```

</details>

## Task 3 - GitLab runner uses `if-not-present` pull policy on a shared fleet

```toml
[runners.docker]
  image = "alpine:3.20"
  pull_policy = "if-not-present"
```

### Prompt

Why is this a problem in mixed-trust shared runners?

<details>

<summary><strong>Reveal the worked answer</strong></summary>

#### Why risky

A private image pulled by one job may remain cached locally and be reused by another job that should not have access to it.

#### Better pattern

* prefer `always` on mixed-trust shared fleets;
* or use `never` only when administrators pre-stage an approved local image set;
* avoid shared runner trust mixing.

</details>

## Task 4 - Self-hosted GitHub runner on a public repo

### Scenario

A team attaches a self-hosted runner to a public repo because they need access to a private network dependency during CI.

### Prompt

Explain the risk and the safer alternatives.

<details>

<summary><strong>Reveal the worked answer</strong></summary>

#### Risk

Any hostile pull request path may reach the self-hosted environment, persist compromise, steal secrets, or pivot internally.

#### Better alternatives

* keep untrusted PR testing on GitHub-hosted runners;
* move internal integration tests behind a reviewed promotion step;
* use a separate low-trust isolated runner fleet with no secret or private-network reach;
* use service virtualization or controlled artifact mirrors.

</details>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.product-security.expert/learning-labs-interview-and-templates/index-1/ci-cd-and-runner-security-assessment-pack.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
