Chapter 23Lesson 02210–270 min

Secrets, Credentials, Environment Isolation, and Security Hygiene: Guided Hands-On Workflow

Build a disposable fake-secret pipeline: source from environment, wrap as Secret, enforce a target guard, verify masking, demonstrate one intentional fake disclosure, scan artifacts, and clean process state.

Local labFake secrets onlyArtifact scanProcess boundaryCleanup

Learning objectives

  • Create a Secret-typed variable from an environment variable without putting the value in source.
  • Pass Secret to a typed custom keyword while keeping domain result evidence non-sensitive.
  • Use an allowlist before any credential-bearing action.
  • Demonstrate and detect an unsafe plaintext boundary with a fake sentinel.
  • Prove environment and artifact cleanup independently.

Current compatibility baseline — verified 2026-08-31. Robot Framework 7.4.2 is the stable course baseline and requires Python 3.8+. Secret variables and robot.api.types.Secret are new in Robot Framework 7.4. Secret values are masked in Robot's own argument/return representations, but they are not encrypted, and code can access the real value through .value. The mandatory labs use only a deliberately fake value, a synthetic allowlisted target, local files under an isolated temporary/project directory, and Robot Framework core/standard libraries. No real account, browser, API, database, SSH service, Pabot, CI provider, container runtime, secret manager, paid platform, or production system is required. Robot Framework 7.5b1 is prerelease and is not required.

1. Scenario and ownership

Create rf23-secret-lab/ with one Robot suite, one small Python library, one artifact scanner, and isolated output directories. The token is deliberately fake and never leaves the local machine. The safe run should contain no raw sentinel in Robot result artifacts. A separate diagnostic run intentionally accesses .value and must be detected by the scanner.

rf23-secret-lab/
├── libraries/
│   └── secret_guard.py
├── tools/
│   └── scan_artifacts.py
├── suites/
│   └── security.robot
└── evidence/
    ├── safe/
    └── unsafe/

2. Setup and preflight

mkdir -p rf23-secret-lab/libraries rf23-secret-lab/tools rf23-secret-lab/suites rf23-secret-lab/evidence
cd rf23-secret-lab
python -m venv .venv
# Bash/zsh
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install robotframework==7.4.2
export RF23_FAKE_TOKEN='RF23_FAKE_ONLY_7z9q'
python --version
python -m robot --version
python -c "import os; print('token present:', 'RF23_FAKE_TOKEN' in os.environ)"
New-Item -ItemType Directory -Force rf23-secret-lab/libraries,rf23-secret-lab/tools,rf23-secret-lab/suites,rf23-secret-lab/evidence | Out-Null
Set-Location rf23-secret-lab
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install robotframework==7.4.2
$env:RF23_FAKE_TOKEN='RF23_FAKE_ONLY_7z9q'
python --version
python -m robot --version
python -c "import os; print('token present:', 'RF23_FAKE_TOKEN' in os.environ)"

Do not run echo $RF23_FAKE_TOKEN or its PowerShell equivalent. Presence is enough for preflight. The virtual environment owns the Robot installation; your shell owns the parent environment variable.

3. Build the Secret-aware library and target guard

# libraries/secret_guard.py
from robot.api import Failure, logger
from robot.api.deco import keyword, library
from robot.api.types import Secret

_ALLOWED_TARGETS = {"local-synthetic"}

@library(scope="TEST")
class SecretGuard:
    @keyword
    def assert_allowed_target(self, target: str) -> None:
        if target not in _ALLOWED_TARGETS:
            raise Failure(f"Target {target!r} is not allowlisted.")
        logger.info(f"Target guard passed for {target!r}.")

    @keyword
    def use_fake_secret_safely(self, token: Secret) -> str:
        # Real code would hand token.value only to the minimum required client API.
        if not token.value.startswith("RF23_FAKE_ONLY_"):
            raise Failure("Lab accepts only the documented fake-token prefix.")
        logger.info(f"Received Secret object {token}; raw value was not logged.")
        return "synthetic-operation-accepted"

    @keyword
    def unsafe_unwrap_for_demonstration(self, token: Secret) -> str:
        # INTENTIONALLY UNSAFE. Use only with the fake lab value.
        return token.value

SecretGuard uses TEST scope so no credential-related instance state survives between tests. The “unsafe” keyword exists only to create a controlled failure demonstration. It must never be reused as a production helper.

4. Create the Robot suite

*** Settings ***
Library    ../libraries/secret_guard.py
Library    OperatingSystem
Library    Process
Library    Collections

*** Variables ***
${TARGET}           local-synthetic
${TOKEN: Secret}    %{RF23_FAKE_TOKEN}

*** Test Cases ***
Safe Secret Path
    Assert Allowed Target    ${TARGET}
    ${status}=    Use Fake Secret Safely    ${TOKEN}
    Should Be Equal    ${status}    synthetic-operation-accepted
    Log    Safe path completed without unwrapping the token.

Secret-Aware Environment Operation
    Set Environment Variable    RF23_CHILD_TOKEN    ${TOKEN}
    ${python}=    Evaluate    sys.executable    modules=sys
    &{env}=    Create Dictionary    RF23_CHILD_TOKEN=${TOKEN}
    ${result}=    Run Process    ${python}    -c
    ...    import os; print('present' if os.getenv('RF23_CHILD_TOKEN') else 'missing')
    ...    env=${env}
    Should Be Equal    ${result.stdout}    present
    Remove Environment Variable    RF23_CHILD_TOKEN

Unsafe Fake Disclosure
    [Tags]    unsafe-demo
    Assert Allowed Target    ${TARGET}
    ${plaintext}=    Unsafe Unwrap For Demonstration    ${TOKEN}
    Log    INTENTIONAL FAKE LEAK: ${plaintext}

The first test never asks for .value. The second demonstrates a separate boundary: Robot can keep the parent configuration representation redacted while a child process still receives the real value. The third test intentionally creates plaintext and is excluded from normal execution.

5. Safe run and before/after evidence

python -m robot --exclude unsafe-demo --outputdir evidence/safe suites/security.robot

# Expected: PASS. Inspect artifacts without printing the token.
find evidence/safe -maxdepth 1 -type f -print 2>/dev/null || true
python -m robot --exclude unsafe-demo --outputdir evidence/safe suites/security.robot
Get-ChildItem evidence/safe -File | Select-Object Name,Length

Expected evidence includes PASS status, target-guard messages, the word <secret> or otherwise masked argument rendering where appropriate, child-process result present, and no raw fake sentinel. Notice that proving the child saw the value does not require printing the value itself.

6. Scan artifacts without passing the secret on the command line

# tools/scan_artifacts.py
import os
import pathlib
import sys

root = pathlib.Path(sys.argv[1])
needle = os.environ["RF23_FAKE_TOKEN"].encode()
hits = []
for path in root.rglob("*"):
    if path.is_file():
        try:
            data = path.read_bytes()
        except OSError:
            continue
        if needle in data:
            hits.append(str(path.relative_to(root)))

if hits:
    print("FAKE secret sentinel found in:")
    for hit in hits:
        print(f"  - {hit}")
    raise SystemExit(1)
print("No raw fake secret sentinel found.")
python tools/scan_artifacts.py evidence/safe
# Expected exit code: 0

For real secrets, content scanning needs care: providing the credential itself to a scanner can create another disclosure path. Production secret scanners commonly look for patterns, known leaked identifiers, or repository history rather than requiring operators to copy a live credential into a command.

7. Controlled unsafe demonstration

FAKE VALUE ONLY. This test intentionally writes the fake token into Robot evidence. Do not substitute a real credential.

python -m robot --include unsafe-demo --outputdir evidence/unsafe suites/security.robot
python tools/scan_artifacts.py evidence/unsafe
# Expected scanner exit code: 1 and one or more artifact filenames.

The Robot test itself can pass while the security scan fails. That is intentional: functional correctness and evidence hygiene are independent quality gates.

8. Cleanup and rollback

# Preserve evidence until you have finished the comparison. Then:
unset RF23_FAKE_TOKEN
rm -rf evidence/safe evidence/unsafe
python -c "import os; print('token present:', 'RF23_FAKE_TOKEN' in os.environ)"
Remove-Item Env:RF23_FAKE_TOKEN -ErrorAction SilentlyContinue
Remove-Item evidence/safe,evidence/unsafe -Recurse -Force -ErrorAction SilentlyContinue
python -c "import os; print('token present:', 'RF23_FAKE_TOKEN' in os.environ)"

Robot's Remove Environment Variable can only mutate the Robot process environment. It cannot remove an environment variable from the parent shell that launched Robot. That distinction is part of environment isolation.

9. Challenge: choose the right layer

You need a real API token in CI. The API library is known to dump request headers at DEBUG. Choose the design change: (a) rely on Robot Secret and enable DEBUG, (b) disable/avoid sensitive transport logging and pass the value only to the minimum client call, while using non-secret request IDs as evidence, or (c) log the token hash to prove identity.

Answer target: choose (b). Robot masking does not control third-party request dumps, and deterministic hashes can still become sensitive metadata for low-entropy secrets.

10. Summary and bridge

The safe lab proves three separate controls: target allowlisting, Secret-aware Robot data flow, and artifact scanning. The unsafe run proves that unwrapping a Secret crosses a hard boundary. Lesson 3 turns those observations into design choices for CI stores, environment variables, external clients, identity scope, and retention.

Knowledge check

Why does the safe artifact scan run after the Robot test?

Why is RF23_CHILD_TOKEN removed inside Robot and the parent RF23_FAKE_TOKEN removed in the shell?

The unsafe disclosure test passes. Is that a green pipeline?

Why use a dedicated fake-token prefix in the custom library?

Next lesson

Secrets, Credentials, Environment Isolation, and Security Hygiene: Configuration, Design Patterns, and Trade-Offs

Continue with Secrets, Credentials, Environment Isolation, and Security Hygiene: Configuration, Design Patterns, and Trade-Offs. It builds directly on the state, evidence, and operating assumptions established here, so carry those constraints forward rather than treating the next page as an isolated topic.

References and version anchors

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.