Multibranch Pipelines, Branch Sources, Pull Request Discovery, Jenkinsfile Trust, and Branch Indexing: Guided Hands-On Workflow and Core Operations
Create a disposable local repository, index multiple branches, prove which Jenkinsfile/source revision each branch job executes, change one branch safely, inspect indexing evidence, and practice bounded orphaned-item retention. A PR-like branch models discovery locally while provider-specific fork trust remains a separate security control.
Learning objectives
- Create a disposable local Git repository suitable for a Multibranch Pipeline lab.
- Discover branches, inspect indexing logs and verify exact Jenkinsfile/source revisions.
- Change one branch Jenkinsfile and prove only the expected child revision changes.
- Simulate an untrusted contribution without making protected credentials available.
- Delete a branch and verify bounded orphaned-item behavior.
1. Lab topology and preflight
The mandatory path stays free and local. Use the existing disposable
Jenkins 2.568.3 LTS controller with Java 21, one
disposable low-privilege agent labeled ch22-untrusted,
Git 5.10.1 and Git Client 6.6.1. The
controller and agent must both be able to read the same local bare
repository path /lab-scm/ch22-lab.git. For
containerized Jenkins, bind-mount the same synthetic repository path
into the controller and agent lab containers.
2. Create a synthetic bare repository
Run these commands outside Jenkins in a disposable lab directory. They create a bare remote and three branches with intentionally visible Jenkinsfile markers.
set -eu
LAB=/tmp/ch22-author
REMOTE=/lab-scm/ch22-lab.git
rm -rf "$LAB" "$REMOTE"
mkdir -p "$(dirname "$REMOTE")"
git init --bare "$REMOTE"
git clone "$REMOTE" "$LAB"
cd "$LAB"
git config user.name 'DevOps Academy Lab'
git config user.email 'lab@example.invalid'
git switch -c main
cat > Jenkinsfile <<'EOF'
pipeline {
agent { label 'ch22-untrusted' }
stages {
stage('Evidence') {
steps {
sh '''set -eu
printf 'branch=%s build=%s node=%s workspace=%s\\n' "$BRANCH_NAME" "$BUILD_NUMBER" "$NODE_NAME" "$WORKSPACE"
git rev-parse HEAD | tee source-sha.txt
printf 'jenkinsfile_marker=main-v1\\n' | tee jenkinsfile-marker.txt
'''
archiveArtifacts artifacts: 'source-sha.txt,jenkinsfile-marker.txt', fingerprint: true
}
}
}
}
EOF
printf 'synthetic app v1\n' > app.txt
git add Jenkinsfile app.txt
git commit -m 'main: initial synthetic pipeline'
git push -u origin main
git switch -c feature-safe
sed -i 's/main-v1/feature-safe-v1/' Jenkinsfile
printf 'feature change\n' >> app.txt
git add . && git commit -m 'feature: safe branch'
git push -u origin feature-safe
git switch main
git switch -c pr-untrusted
sed -i 's/main-v1/pr-untrusted-v1/' Jenkinsfile
printf 'untrusted contribution simulation\n' >> app.txt
git add . && git commit -m 'simulation: untrusted contribution'
git push -u origin pr-untrusted
git log --all --decorate --oneline --graph
pr-untrusted is intentionally just a branch. It gives
us a reproducible candidate to discuss trust without pretending that
plain Git can identify a fork author.
3. Create the Multibranch Pipeline
In Jenkins create
New Item → Multibranch Pipeline named
ch22-multibranch. Add a Git branch source pointing to
file:///lab-scm/ch22-lab.git (or an equivalent
reachable local URL). Leave credentials empty because the repository
is synthetic and local. Keep the default Jenkinsfile path
Jenkinsfile.
Configure an orphaned-item strategy appropriate to the lab, for example retaining a small number of old branch jobs/builds for review rather than deleting immediately. Record the exact values in your evidence packet.
4. Inspect the first branch index
Saving the project should trigger indexing. Open
Scan Multibranch Pipeline Log and preserve the
first log. Confirm that Jenkins discovers main,
feature-safe and pr-untrusted and creates
child jobs for branches containing a Jenkinsfile.
Record the parent full name and the three child names. Child names can be encoded when SCM head names contain characters that are unsafe in item paths; never derive security policy from display-name formatting.
5. Prove which source and Jenkinsfile each child runs
Run or inspect one build per branch. The archived
source-sha.txt must match the Git commit for that
branch at build time, and jenkinsfile-marker.txt must
match the branch-specific marker. Also record the build cause and
BRANCH_NAME.
cd /tmp/ch22-author
for b in main feature-safe pr-untrusted; do
printf '%-14s ' "$b"
git rev-parse "$b"
done
This separates “the parent indexed branch X” from “child X built commit Y using Jenkinsfile content Z.”
6. Change one branch Jenkinsfile and re-index
Modify only feature-safe:
cd /tmp/ch22-author
git switch feature-safe
sed -i 's/feature-safe-v1/feature-safe-v2/' Jenkinsfile
git add Jenkinsfile
git commit -m 'feature: update pipeline marker'
git push origin feature-safe
Trigger a branch index if your local source has no webhook/event
integration. Verify the feature-safe child builds the
new source revision and marker while main remains
attributable to its own revision. Preserve both build numbers.
7. Simulate an untrusted contribution correctly
Treat pr-untrusted as contributor-controlled code for
discussion. The lab boundary is external to the branch content: the
Multibranch project has no protected credential configured or
reachable, and the only eligible agent is a disposable low-privilege
ch22-untrusted worker. Do not create a fake “production
token” and rely on masking.
Now edit the branch Jenkinsfile so it tries to request a
nonexistent credential ID such as
ch22-protected-simulation. The build should fail
because that credential does not exist. Preserve the failure as
evidence that the lab did not silently substitute a real secret.
8. Optional provider-specific trust path
With a provider branch-source plugin such as GitHub Branch Source, pull requests are separate SCM heads and fork trust can determine which revision supplies trusted files. Current Jenkins documentation describes strategies such as trusting nobody or approved collaborators. Use provider documentation for exact traits and never test this against an organization repository with real deployment credentials.
The production objective is simple: untrusted candidate code may be tested, but it cannot rewrite the control path that grants protected secrets or privileged agents.
9. Delete a branch and inspect orphaning
cd /tmp/ch22-author
git push origin --delete feature-safe
Run a branch index and verify how feature-safe changes
according to the recorded orphaned-item strategy. Do not manually
delete the child first; you want evidence of Jenkins applying
policy.
10. Challenge: choose the correct layer
A new fork PR appears, Jenkins indexes it successfully, and the build then cannot access a signing credential. Is the correct fix “add the signing credential to the Multibranch parent”? No. First determine whether the PR is trusted. For an untrusted contribution, the denial is the desired boundary; move signing to a trusted post-merge/release path rather than broadening credentials.
11. Cleanup
Export the indexing log and selected build evidence, then remove
only ch22-multibranch, the synthetic repository/mount
and the disposable agent if they were created for this chapter. Do
not touch production SCM hooks or credentials.
Knowledge check
Answer before revealing the explanation.
1. Why does the local lab use a bare repository and plain Git branch discovery?
It provides a fully free, disposable way to learn indexing, per-branch jobs, Jenkinsfile/source identity and retention without requiring a real SCM account or credential.
2. Why is the pr-untrusted branch only a simulation of a fork PR?
Plain Git branch discovery has no provider identity or fork-trust trait. It can demonstrate an untrusted contribution workflow, but it cannot reproduce a GitHub/GitLab/Bitbucket pull-request trust decision.
3. What evidence proves which Jenkinsfile revision ran?
Record the child job full name, build number/URL, build cause, BRANCH_NAME, exact Git SHA and a checksum/content marker from the Jenkinsfile or source revision.
4. Why should the lab keep protected credentials absent from all branch jobs?
Because the local simulation cannot enforce provider fork trust. With no protected credential available, an edited branch Jenkinsfile cannot exfiltrate a secret that was never exposed to that project.
5. What should happen when a test branch is deleted?
A later branch index should mark/remove the corresponding child according to the configured orphaned-item strategy while retained build evidence follows that policy.
Official references and version notes
-
Jenkins LTS changelog
— chapter baseline
Jenkins 2.568.3 LTS, released 2026-09-02 and tested with Java 21 and 25; labs use Java 21. - Jenkins: Branches and Pull Requests — Multibranch discovery, branch child jobs, indexing and change-request environment variables.
-
Pipeline: Multibranch
— version
841.vec5b_9e1806ec, requiring Jenkins 2.504.3. -
Branch API
— version
2.1280.v0d4e5b_b_460ef; documents Multibranch event/indexing log locations and routing. -
SCM API
— version
728.vc30dcf7a_0df5. -
Git plugin
— version
5.10.1. -
Git Client plugin
— version
6.6.1; current releases include fixes for earlier command-injection issues on agents. -
GitHub Branch Source
— provider-specific optional reference, version
1983.vfa_27ed961853, requiring Jenkins 2.541.1. - Pipeline: Multibranch step/reference — documents provider pull-request trust strategies and trusted-file behavior.
-
Credentials API
— version
1511.v2e3cb_0008ef0; credentials remain a separate authorization boundary from SCM discovery.
Version note — 2026-09-17: executable local
examples assume Jenkins 2.568.3 LTS, Java 21, Pipeline:
Multibranch 841.vec5b_9e1806ec, Branch API
2.1280.v0d4e5b_b_460ef, SCM API
728.vc30dcf7a_0df5, Git 5.10.1, and Git
Client 6.6.1. GitHub Branch Source
1983.vfa_27ed961853 is used only to explain a real
provider fork/PR trust model; the mandatory local lab does not
require an external SCM account or real SCM credential. Re-check
provider plugin advisories and trust semantics before production
adoption.
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.