Study Guide · 350-901

350-901 Cheat Sheet

421 entries · 24 chapters · 4 domains

Network Automation

Network Automation with Ansible

Read full chapter

Cheat sheet

Sharp facts the exam loves — scan these before test day.

cisco.ios.ios_vlans with state replaced converges the VLAN database

The cisco.ios.ios_vlans resource module is the modern declarative module for VLANs; with state: replaced it overwrites the config of the listed VLANs so the running VLAN entries match the playbook exactly, giving idempotent convergence rather than blind CLI pushes.

Trap Distractor uses the deprecated singular cisco.ios.ios_vlan which only adds VLANs and cannot declaratively replace the set.

4 questions test this
Resource-module states: merged, replaced, overridden, deleted

Ansible network resource modules accept state values merged (default, additive), replaced (replace only the specified resources), overridden (replace and remove every resource not listed), and deleted. For VLANs, overridden deletes all VLANs absent from the playbook while replaced touches only the listed ones.

Trap Confusing replaced (per-resource) with overridden (whole-list) — overridden will wipe VLANs you did not list.

7 questions test this
gathered, rendered, and parsed states never touch the device

The gathered state returns current config as structured facts, rendered produces device CLI from the module input without connecting, and parsed converts a supplied running-config text into structured data. None of these three push configuration to the device.

3 questions test this
The singular ios_vlan module was deprecated and removed

The legacy cisco.ios.ios_vlan (singular) module was deprecated and removed from the cisco.ios collection after 2022-06-01; playbooks should use the plural cisco.ios.ios_vlans resource module for declarative, idempotent VLAN management.

cisco.ios.ios_ospfv2 manages OSPF process config declaratively

cisco.ios.ios_ospfv2 manages the OSPFv2 process (areas, networks, redistribution, timers) as structured data, while cisco.ios.ios_ospf_interfaces manages per-interface OSPF settings; state: merged adds, replaced rewrites one process, overridden rewrites all.

Trap Using the generic ios_config module for OSPF instead of the declarative ios_ospfv2 resource module.

4 questions test this
cisco.ios.ios_acls manages ACLs as structured ACEs

cisco.ios.ios_acls manages named and numbered IPv4/IPv6 ACLs as a structured list of ACEs; state: replaced rewrites a single named ACL to the given ACEs, while state: overridden reconciles ALL ACLs on the device to the module's definition.

Trap Assuming state: replaced touches every ACL on the device (it is scoped to the named ACL; overridden is the device-wide one).

3 questions test this
ios_interfaces vs ios_l3_interfaces split interface concerns

cisco.ios.ios_interfaces manages L1/L2 interface attributes (description, enabled, mtu, speed, duplex); cisco.ios.ios_l3_interfaces manages the L3 addressing (IPv4/IPv6) on those interfaces — the correct module depends on which layer of interface setting is being automated.

Trap Trying to set an IP address with ios_interfaces (addressing lives in ios_l3_interfaces).

4 questions test this
ios_config parents builds a hierarchical config block

cisco.ios.ios_config pushes raw CLI imperatively; the parents list places the lines/commands into a config hierarchy, e.g. parents: interface GigabitEthernet1/0/1 with lines: ip access-group ACL_IN in enters that interface context before applying the lines.

5 questions test this
ios_config match none disables idempotent diffing

ios_config defaults to match: line, comparing each candidate line against the running-config and sending only missing lines; setting match: none disables that comparison so every command is pushed on every run, destroying idempotency.

Trap Assuming ios_config is always idempotent — with match: none (or no diff-aware model) it re-pushes lines every run.

5 questions test this
save_when: modified writes startup-config only on change

ios_config's save_when: modified copies running-config to startup-config only when the task actually changed the running-config, preserving idempotency; save_when: always writes every run and reports changed each time.

5 questions test this
ios_config is imperative; resource modules are declarative

For structured features (VLANs, OSPF, interfaces, ACLs) prefer the declarative resource modules (ios_vlans, ios_ospfv2, ios_l3_interfaces, ios_acls) which model and converge state; reserve ios_config for raw CLI that no resource module covers.

1 question tests this
network_cli, netconf, and httpapi connection plugins

Network devices set ansible_connection to ansible.netcommon.network_cli (SSH CLI), ansible.netcommon.netconf (NETCONF/830), or ansible.netcommon.httpapi (REST/RESTCONF), and ansible_network_os: cisco.ios.ios to select the platform parser and command set.

8 questions test this
become_method enable reaches privileged config mode

For network_cli, ansible_user/ansible_password authenticate the SSH session and become: true with become_method: enable (optionally ansible_become_password) elevates to privileged EXEC so configuration tasks can run.

2 questions test this
group_vars and host_vars scope connection variables

Inventory groups let group_vars/<group>.yml set shared connection variables while host_vars/<host>.yml overrides per device; this keeps credentials and ansible_network_os out of playbooks and scoped correctly.

2 questions test this
httpapi connection drives RESTCONF and controller APIs

The httpapi connection plugin (with ansible_httpapi_use_ssl: true and ansible_httpapi_port: 443) is used for RESTCONF and controller APIs such as Cisco Catalyst Center, where modules exchange JSON over HTTPS rather than screen-scraping CLI.

3 questions test this
ansible-vault encrypts secrets at rest with AES256

ansible-vault encrypt protects a var file with AES256 so credentials stay ciphertext in Git; ansible-vault encrypt_string embeds a single encrypted value inline in an otherwise plaintext vars file for selective secrecy.

4 questions test this
Vault password is supplied only at runtime

The decryption key is provided at run time via --ask-vault-pass or --vault-password-file, and --vault-id label@source supports multiple vaults; the plaintext secret never lives on disk or in source control.

6 questions test this
Storing the vault key in the repo defeats the purpose

Committing the vault password (or a symmetric key) alongside the encrypted file gives no real protection because anyone with repo access can decrypt; the key must come from an out-of-band source or a secrets manager at runtime.

Trap Encrypting the vars file but committing the vault password file next to it is a common secret-management anti-pattern.

Idempotency means re-runs report zero changes

An idempotent task reports changed only when it actually altered device state; re-running a fully converged playbook against the same devices yields ok with changed=0, which is the signal that the desired state already matches.

3 questions test this
Check mode previews changes without applying them

Running a playbook with --check (check mode) has resource modules compute and report the changes they would make without pushing anything, and --diff shows the exact config delta; together they give a safe dry-run before a real apply.

1 question tests this
Roles standardize layout; handlers run once when notified

A role uses the standard tasks/ handlers/ templates/ vars/ defaults/ meta/ layout for reuse; a handler runs once at the end of the play and only when a task that notifys it reported changed, ideal for a single save or service reload.

2 questions test this
Jinja2 templates and loops render per-device config

Jinja2 templates plus loop/with_items render device-specific values (VLAN IDs, ACL entries, OSPF areas) from inventory variables, and when conditionals gate tasks so one playbook adapts across a heterogeneous fleet.

1 question tests this
Ansible block/rescue/always enables change rollback

In Ansible, block groups tasks; rescue runs its tasks only if a task in the block fails (place restore/undo steps here); always runs regardless — together they give a change task automated rollback when a push or post-change verify fails, instead of leaving the device half-configured.

Trap Believing a failed task automatically rolls back prior changes without a rescue block.

1 question tests this
failed_when and ignore_errors shape failure handling

failed_when defines a custom failure condition on a task (e.g. fail when command output contains 'Invalid'), and ignore_errors: true lets the play continue past a failure so a later cleanup or rescue can run — both control when the recovery path triggers.

Trap Confusing ignore_errors (continue past failure) with failed_when (redefine what counts as failure).

2 questions test this
cisco.ios.ios_facts collects hardware/software inventory

cisco.ios.ios_facts gathers device facts into ansible_net_* variables (ansible_net_model, ansible_net_serialnum, ansible_net_version, ansible_net_hostname) — the standard way to collect hardware/software inventory for an asset database; gather_subset tunes what is collected.

Trap Expecting a resource module's 'gathered' state to return hardware serial/model — it returns per-feature CONFIG, not asset inventory.

2 questions test this
RESTCONF content=nonconfig returns operational state

A RESTCONF GET with query content=nonconfig returns operational (read-only) state such as interface oper-status and counters, while content=config returns only configuration and omitting content returns both — how live device state is read without changing config.

Trap Assuming a plain RESTCONF GET on a data node returns only configuration data.

3 questions test this
NETCONF returns config+state, config only

NETCONF returns configuration AND operational state, whereas returns configuration only from a named datastore — use to read operational/asset data such as counters or neighbor state.

Trap Using to read operational counters (it returns configuration only).

2 questions test this
Python retrieves and parses live device state

Python reads live device state by issuing ncclient get() RPCs or netmiko send_command show output, then parsing it into structured data with a Genie/pyATS parser or TextFSM for programmatic asset/state processing rather than screen-scraping raw text.

Trap Screen-scraping raw show output instead of parsing it into structured data.

4 questions test this

Network Automation with Terraform

Read full chapter

Cheat sheet

Sharp facts the exam loves — scan these before test day.

State maps config to real resources and is authoritative

Terraform's terraform.tfstate is the source of truth mapping HCL resources to real objects; a state file that is local to one runner is invisible to others, so a second engineer's run believes the resources do not exist and may recreate or destroy them.

12 questions test this
Remote backends with state locking serialize applies

Moving state to a remote backend (Amazon S3 with native use_lockfile locking, Google Cloud Storage, or HCP Terraform) shares one authoritative state and enables state locking so only one terraform apply can mutate state at a time, preventing concurrent destructive operations.

Trap terraform refresh or -var files are offered as the fix, but only a shared, locked remote backend addresses the concurrency root cause.

6 questions test this
Refresh reconciles state but cannot invent missing resources

terraform apply -refresh-only (formerly terraform refresh) updates state to match the real world, but it cannot synthesize resources created under a different engineer's separate state file, so it does not solve shared-state or concurrency problems.

6 questions test this
terraform import adopts pre-existing resources into state

terraform import <resource_address> <id> brings an already-existing, unmanaged object under Terraform management by recording it in state; without import, Terraform would try to create a duplicate of a resource it does not know about.

8 questions test this
Terraform state stores secrets in plaintext

terraform.tfstate persists every managed resource attribute — including passwords, tokens, and keys — in plaintext, so the state file must live in an encrypted, access-controlled remote backend and never be committed to Git; this secrecy concern is separate from state locking.

Trap Committing terraform.tfstate to the repo or assuming state locking also protects its confidentiality.

terraform init installs providers and initializes the backend

terraform init downloads the providers declared in required_providers and initializes the configured backend; it must run before plan/apply and again whenever providers, modules, or the backend change.

1 question tests this
plan -out guarantees apply executes exactly that plan

terraform plan computes an execution plan (the diff) and terraform apply executes it; saving the plan with -out=plan.tfplan and applying that file guarantees apply performs exactly the reviewed actions with no re-computation.

5 questions test this
Plan action symbols: + create, - destroy, ~ update, -/+ replace

In plan output + creates, - destroys, ~ updates in place, and -/+ replaces (destroy then create) a resource; a -/+ on a networking resource signals a disruptive recreation, often driven by a change to an immutable attribute.

5 questions test this
destroy removes managed resources; -target scopes actions

terraform destroy removes all resources tracked in state, while -target=<address> scopes a plan/apply/destroy to a single resource or module; -target is a surgical escape hatch, not a routine workflow.

required_providers pins provider source and version

The terraform { required_providers { iosxe = { source = "CiscoDevNet/iosxe", version = "..." } } } block declares each plugin's registry source and a version constraint; a matching provider "iosxe" block then sets url, username, password, and insecure.

5 questions test this
The IOS-XE provider manages devices over RESTCONF

The CiscoDevNet/iosxe Terraform provider configures Catalyst/IOS-XE devices by driving their model-driven API — NETCONF over SSH by default, or RESTCONF when you set protocol = "restconf" — exposing resources such as iosxe_vlan, iosxe_interface_ethernet, and iosxe_ospf whose attributes map to native YANG leaves.

7 questions test this
Cisco publishes providers for IOS-XE, NX-OS, ACI, SD-WAN, Catalyst Center

Cisco maintains Terraform providers including iosxe, nxos, aci, sdwan, and catalystcenter, so the same HCL/state/plan workflow spans device-level and controller-level automation across product lines.

5 questions test this
Provider resource attributes mirror the underlying YANG model

Each Cisco provider resource's arguments correspond to leaves in the device's YANG model (for example an iosxe_vlan resource's vlan_id and name), so Terraform effectively becomes a declarative front end over model-driven configuration.

HCL declares desired end state, not procedural steps

HCL is declarative: you describe the desired end state of resources and Terraform's core computes the create/update/destroy actions to reach it, in contrast to an imperative script where you code each step and ordering yourself.

4 questions test this
plan detects drift between state and real infrastructure

Configuration drift occurs when real infrastructure diverges from state (e.g., a manual out-of-band CLI change); terraform plan refreshes and surfaces that drift as a diff, and a subsequent apply re-converges the device to the HCL-defined state.

4 questions test this
Variables, modules, and for_each parameterize and scale config

Input variables, locals, and outputs parameterize a configuration; reusable modules package it; and count/for_each iterate a resource across a set (e.g., one iosxe_vlan per entry in a VLAN map) for DRY, scalable definitions.

5 questions test this
lifecycle meta-arguments control replacement behavior

The lifecycle block tunes resource replacement: prevent_destroy blocks accidental deletion, create_before_destroy avoids an outage during replacement, and ignore_changes tells Terraform to disregard drift on specific attributes.

Network Automation with RESTCONF

Read full chapter
  • RESTCONF root exposes /data and /operations resources
  • YANG containers and lists map to URL path segments
  • The first node and cross-module nodes carry the module prefix
  • content, depth, and fields query parameters shape retrieval
  • POST creates a new child data resource
  • PUT creates-or-replaces the target and is idempotent
  • PATCH merges partial edits; DELETE removes the resource
  • RESTCONF status codes: 201, 204, 400, 404, 409
  • yang-data+json/+xml are the RFC 8040 media types
  • Content-Type and Accept govern request vs response encoding
  • Errors are returned as ietf-restconf:errors
  • IOS-XE enables RESTCONF over HTTPS/443
  • Native model nests IPv4 under ip/address/primary with mask
  • Native and IETF/OpenConfig models have distinct URIs
  • JSON keys must match YANG leaf names exactly
  • PUT body wraps the target container, module-qualified

Unlock with Premium — includes all practice exams and the complete study guide.

Network Automation with Python

Read full chapter
  • ncclient connects to NETCONF on port 830
  • edit_config to candidate then commit is transactional
  • lock/unlock protect the datastore during edits
  • get_config with a subtree filter retrieves modeled data
  • RESTCONF edits running directly; NETCONF has candidate+commit
  • requests sends RESTCONF calls with yang-data headers
  • requests.Session reuses the connection and persists auth
  • raise_for_status surfaces HTTP errors explicitly
  • The json= parameter serializes a dict and sets Content-Type
  • netmiko ConnectHandler screen-scrapes CLI over SSH
  • use_textfsm parses raw show output into structured data
  • paramiko is the low-level SSHv2 library netmiko wraps
  • CLI scraping is a fallback to model-driven interfaces
  • asyncio runs concurrent I/O in one thread via an event loop
  • gather fans out tasks; Semaphore bounds concurrency
  • A blocking call stalls the entire event loop
  • asyncio helps I/O-bound work, not CPU-bound work
  • A decorator wraps a function to add cross-cutting behavior
  • A parameterized decorator is a decorator factory
  • pyproject.toml + wheels package automation code
  • Virtual environments and pinned requirements isolate deps

Unlock with Premium — includes all practice exams and the complete study guide.

Selecting the Network Automation Approach

Read full chapter
  • IaC frameworks give declarative, versionable, idempotent config
  • Low-code/no-code trades flexibility for speed and low skill
  • Custom applications maximize flexibility at higher cost
  • Approach selection weighs scale, skills, flexibility, maintainability
  • Declarative tools converge on a desired end state
  • Imperative approaches require you to manage steps and idempotency
  • Idempotency is a core selection criterion
  • Model-driven interfaces beat CLI scraping for robustness
  • NSO uses a transactional CDB and FASTMAP for service orchestration
  • Catalyst Center Intent API and SD-WAN vManage API automate fabrics
  • Match the platform to the automation scope

Unlock with Premium — includes all practice exams and the complete study guide.

Consuming REST APIs at Scale

Read full chapter
  • Offset/limit pagination iterates until a short page returns
  • Cursor pagination follows nextPage or Link rel=next
  • A single response rarely holds the full result set
  • The server caps page size regardless of the client request
  • 429 Too Many Requests must honor Retry-After
  • Exponential backoff with jitter spreads retries
  • Client-side throttling avoids hitting the limit at all
  • Distinguish retryable from non-retryable responses
  • OAuth2 client-credentials yields a Bearer access token
  • Persistent auth caches and refreshes tokens, not per-request
  • Catalyst Center issues an X-Auth-Token to reuse
  • vManage uses a session cookie plus a CSRF token
  • Handle responses by HTTP status class
  • 401, 403, and 404 demand different reactions
  • Only idempotent methods are safe to blindly retry
  • A requests Retry adapter automates backoff and retry

Unlock with Premium — includes all practice exams and the complete study guide.

Infrastructure as Code

Git Version Control Operations

Read full chapter

Cheat sheet

Sharp facts the exam loves — scan these before test day.

Fast-forward vs three-way merge

git merge <branch> fast-forwards (just advances the pointer, no merge commit) when the current branch is a direct ancestor of the target; otherwise it performs a three-way merge that creates a merge commit with two parents. git merge --no-ff forces a merge commit even when a fast-forward is possible.

Trap Claiming a fast-forward merge always records a merge commit.

1 question tests this
Reading and resolving conflict markers

A merge conflict writes both versions into the file delimited by <<<<<<< HEAD (current branch), ======= (separator), and >>>>>>> <branch> (incoming); the engineer edits to the desired content, deletes all markers, git adds the file, then git commit to finish the merge.

Trap Believing the middle section between ======= and >>>>>>> is your own branch's version.

4 questions test this
Aborting an in-progress merge

git merge --abort restores the working tree and index to the exact state that existed before the merge began, safely discarding a conflicted, in-progress merge without needing a manual reset.

Trap Assuming git reset --hard is the only way to cancel a conflicted merge.

1 question tests this
Conflicted paths reported as Unmerged

While a merge is conflicted, git status lists the files under "Unmerged paths" (both modified); the merge is not complete and cannot be committed until every conflicted path is resolved and staged with git add.

4 questions test this
Resolving a file with --ours or --theirs

During a conflict, git checkout --ours <file> keeps the current branch's version and git checkout --theirs <file> keeps the incoming branch's version, resolving that file wholesale (useful for generated or binary files) before staging it.

Trap Thinking --ours refers to the branch being merged in rather than the current branch.

2 questions test this
git merge --squash stages without committing

git merge --squash <branch> applies the branch's combined changes to the working tree and stages them but does NOT create a merge commit or record the source branch as a parent; the engineer then makes a single ordinary git commit.

Trap Expecting --squash to create the commit automatically.

1 question tests this
Squashing with git reset --soft

git reset --soft HEAD~3 moves the branch tip back three commits while keeping all their changes staged, so one git commit collapses them into a single commit; done on a local, unpushed feature branch this does not rewrite shared history.

Trap Thinking reset --soft discards the changes from the collapsed commits.

2 questions test this
Interactive rebase squash vs fixup

git rebase -i HEAD~3 opens an editor listing the commits; changing pick to squash (s) merges a commit into the prior one and lets you edit the combined message, while fixup (f) merges but discards the squashed commit's message.

Trap Swapping the roles: believing fixup keeps the message and squash drops it.

1 question tests this
Squash only unpushed commits

Squashing rewrites commit SHAs, so squashing commits that were already pushed and shared requires a force push and diverges collaborators' history; squash only local commits that have not been pushed.

Trap Assuming squashing already-pushed commits is safe without a force push.

2 questions test this
cherry-pick copies a commit's changes

git cherry-pick <commit> creates a NEW commit on the current branch that reproduces the changes introduced by the named commit, with a new SHA; the original commit stays where it is (it is copied, not moved).

Trap Thinking cherry-pick moves the commit off its original branch.

2 questions test this
cherry-pick -n stages without committing

git cherry-pick -n (--no-commit) applies the picked commit's changes to the working tree and index but stops before committing, allowing several picks to be combined into one commit.

2 questions test this
cherry-pick commit ranges are exclusive of the start

git cherry-pick A..B picks the commits after A up to and including B — commit A itself is excluded; use A^..B to also include A.

Trap Assuming A..B includes commit A.

1 question tests this
Resuming cherry-pick after a conflict

On a conflict, cherry-pick pauses; resolve the files, git add them, then run git cherry-pick --continue (or --abort to cancel entirely, --skip to drop the current commit).

1 question tests this
cherry-pick -x records provenance

git cherry-pick -x appends a "(cherry picked from commit )" line to the new commit message, recording where the change came from — common when backporting a fix to a release branch.

reset --soft keeps changes staged

git reset --soft <ref> moves HEAD (and the current branch) to but leaves the index and working tree untouched, so the changes from the undone commits remain staged and ready to re-commit.

Trap Believing --soft discards working-tree changes.

6 questions test this
reset --mixed (default) unstages changes

git reset --mixed <ref> — the default when no mode is given — moves HEAD and resets the index to match but leaves the working tree alone, so the changes become unstaged (modified) but are not lost.

Trap Thinking the default reset deletes files from the working tree.

6 questions test this
reset --hard discards working tree

git reset --hard <ref> moves HEAD and forcibly overwrites BOTH the index and the working tree to match , permanently discarding uncommitted changes and the work in the reset-away commits.

Trap Assuming --hard keeps the removed commits' changes staged like --soft.

5 questions test this
reset with a path unstages a file

git reset <file> (i.e. git reset HEAD <file>) unstages that file — the inverse of git add — without changing its working-tree content and without moving HEAD.

2 questions test this
Recovering commits after a reset

Commits orphaned by a reset remain reachable through git reflog until garbage collection; running git reset --hard <sha-from-reflog> restores the branch to a mistakenly-reset commit.

Trap Believing reset --hard is immediately and permanently unrecoverable.

checkout switches branches

git checkout <branch> updates HEAD, the index, and the working tree to the branch tip; git checkout -b <new> creates a new branch and switches to it in one command.

4 questions test this
checkout of a path discards local edits

git checkout -- <file> discards uncommitted working-tree changes to that file by restoring it from the index/HEAD (the modern equivalent is git restore <file>); it overwrites local edits, it does not stage them.

Trap Thinking checkout of a file path stages the file for commit.

2 questions test this
Checking out a commit detaches HEAD

git checkout <commit-sha> (a commit, not a branch) puts the repo in DETACHED HEAD state; new commits made there belong to no branch and become unreachable once you switch away unless you first create a branch to hold them.

Trap Assuming commits made in detached HEAD stay attached to the previously checked-out branch.

3 questions test this
switch and restore split checkout's roles

Modern Git separates checkout's overloaded behavior: git switch <branch> (with -c to create) changes branches and git restore <file> restores file contents, removing the ambiguity of a single overloaded command.

revert adds an inverse commit

git revert <commit> creates a NEW commit that applies the inverse of the named commit's changes, undoing its effect while preserving history — making it the safe way to undo a commit that has already been pushed and pulled by others.

Trap Thinking revert deletes or rewrites the original commit.

4 questions test this
revert vs reset for shared history

git reset rewrites history and is unsafe once commits are pushed, whereas git revert is additive and non-destructive; on a shared branch you undo a bad commit with revert, not reset.

Trap Recommending reset as the safe way to undo an already-pushed commit.

2 questions test this
Reverting a merge needs -m

Reverting a merge commit requires -m <parent-number> (e.g. git revert -m 1 <merge-sha>) to name which parent is the mainline, because a merge has two parents and Git cannot infer which side to preserve.

Trap Assuming a merge commit can be reverted without specifying a mainline parent.

2 questions test this
revert -n stages without committing

git revert -n <commit> stages the inverse changes without creating the commit, letting several reverts be combined into a single commit.

rebase replays commits onto a new base

git rebase <base> replays the current branch's commits one at a time on top of , producing a linear history with NEW SHAs, versus git merge which preserves branch topology by adding a merge commit.

Trap Believing rebase preserves the original commit SHAs.

4 questions test this
The golden rule of rebasing

Never rebase commits that have been pushed and that others may have based work on: rebasing rewrites SHAs, forcing every collaborator to reconcile diverged history. Rebase only local, unshared commits.

Trap Claiming rebasing a shared branch is fine as long as you force-push.

2 questions test this
Resolving conflicts during a rebase

On a rebase conflict Git pauses at the offending commit; resolve, git add, then git rebase --continue. git rebase --abort returns to the pre-rebase state and --skip drops the current commit.

2 questions test this
git pull --rebase keeps history linear

git pull --rebase fetches the upstream and rebases local commits on top of it instead of creating a merge commit, keeping a feature branch's history linear when syncing with the remote.

HEAD~n vs HEAD^n notation

HEAD~n follows the first parent n generations back, while HEAD^ is the first parent and HEAD^2 the SECOND parent of a merge; thus HEAD~2 equals HEAD^^ but is not the same as HEAD^2.

Trap Treating HEAD~2 and HEAD^2 as equivalent.

3 questions test this
reflog records every HEAD movement

git reflog records every movement of HEAD — commits, resets, checkouts, rebases, merges — and is the primary recovery tool for finding "lost" commits after a bad reset or rebase.

1 question tests this
branch -d vs -D

git branch -d <b> refuses to delete a branch that is not merged into the current HEAD (guarding against losing work), whereas git branch -D <b> force-deletes regardless of merge state.

Trap Thinking lowercase -d force-deletes an unmerged branch.

1 question tests this
git stash shelves uncommitted work

git stash saves uncommitted tracked changes and resets the working tree to HEAD; git stash pop reapplies and drops the most recent stash — used to switch branches without committing work in progress.

Diagnosing GitLab CI/CD Failures

Read full chapter

Cheat sheet

Sharp facts the exam loves — scan these before test day.

command not found / ModuleNotFoundError signals a missing dependency

A job that fails with "command not found" or Python's "ModuleNotFoundError: No module named ..." indicates a missing dependency: the runner image or before_script never installed the required package (e.g. pip install -r requirements.txt).

Trap Reading 'command not found' as a YAML syntax error rather than a missing tool.

8 questions test this
Downstream jobs need artifacts declared upstream

If a later job depends on files produced by an earlier job, the producing job must declare them under artifacts:paths:; otherwise the consuming job fails because the artifact was never uploaded and transferred between stages.

Trap Assuming files produced in one job persist to the next without an artifacts declaration.

9 questions test this
cache is best-effort, not a dependency guarantee

cache speeds up repeated jobs by reusing files (pip/npm dirs) but is best-effort and not guaranteed to be present between jobs; runtime dependencies must be installed or passed as artifacts, never relied on from cache.

Trap Treating cache as a reliable way to pass dependencies between stages.

12 questions test this
A minimal base image can omit required tools

Choosing a minimal base image: (e.g. python:3.12-slim, alpine) that lacks tools like git, gcc, or openssh causes "not found" failures; fix by selecting a fuller image or installing the tool in before_script.

4 questions test this
Unpinned dependencies break reproducibility

An unpinned dependency (e.g. ansible with no version) lets a job pull a newer, incompatible release that breaks the pipeline; pinning exact versions in requirements.txt (ansible==9.2.0) makes builds reproducible.

Trap Assuming an unpinned dependency always resolves to the last-known-good version.

8 questions test this
Runner runtime must match code requirements

A job failing on syntax or library APIs can stem from the runner image's language runtime differing from what the code targets (e.g. match statements requiring 3.10+ run on a python:3.8 image); align the image: tag to the required runtime.

8 questions test this
A green pipeline going red without code changes

A pipeline that passed before and now fails with new errors despite no code change usually means a transitively-updated tool shipped a breaking change; reproduce with the committed lockfile and read the tool's changelog to confirm.

8 questions test this
Lockfiles pin the full transitive graph

A committed lockfile (requirements.txt with hashes, poetry.lock, Pipfile.lock) pins the entire transitive dependency graph so CI installs exactly the versions that were tested, eliminating drift between runs.

A non-zero exit code fails the job

A GitLab CI job is marked failed when a command in its script: returns a non-zero exit code; a failing pytest, pyats, or ansible-lint step exits non-zero, halting that stage and blocking every later stage.

Trap Believing a job only fails if the runner itself crashes, not when a test exits non-zero.

14 questions test this
Read the job log top-down to the first error

The job log echoes each command and its output in order; the first non-zero exit and the traceback just above "ERROR: Job failed" localize the fault. Read top-down to the first error, not just the last line.

Trap Assuming the final log line is always the root cause of the failure.

6 questions test this
allow_failure separates advisory from blocking jobs

allow_failure: true lets a job fail without failing the pipeline (it shows as a warning); when it is absent or false, a failed test blocks the pipeline. Use it to distinguish advisory checks from blocking gates.

Trap Thinking allow_failure hides the job from the pipeline rather than merely down-grading its failure to a warning.

6 questions test this
script stops at the first failing command

Each line in script: runs so that the job stops at the first command returning non-zero; a failure early in script: means the later lines never executed, which the log makes visible by their absence.

Building a GitLab CI/CD Pipeline

Read full chapter
  • stages defines execution order; same-stage jobs run in parallel
  • Jobs are placed into stages via stage:
  • A normal job requires a script
  • image selects the container; tags select the runner
  • variables scope: global vs per-job
  • The build stage packages the automation artifact
  • Build exposes outputs via artifacts:paths
  • Building a container image inside CI
  • Build renders intended configs from the source of truth
  • Prevalidation checks the artifact before touching devices
  • Dry-run previews changes without applying
  • Prevalidation is the gate protecting production
  • Cheap prevalidation checks: yamllint and syntax-check
  • Deploy applies validated config to devices
  • Deploy only on the default branch
  • Manual approval and environment tracking on deploy
  • needs makes deploy start as soon as its dependency finishes
  • Post-validation verifies the deployed state
  • pyATS learn/assert in post-validation
  • A failing post-validation closes the deploy loop
  • Publishing test reports to the MR
  • artifacts:paths uploads files for later stages
  • needs changes ordering; dependencies only selects artifacts
  • Ordering without downloading artifacts
  • Artifacts carry build output across the stages
  • rules evaluate if conditions top-down
  • Runner executors: shell, docker, kubernetes
  • Predefined variables drive rules decisions
  • workflow:rules control whole-pipeline creation
  • Masked vs protected GitLab CI/CD variables
  • Injecting secrets into the deploy stage securely

Unlock with Premium — includes all practice exams and the complete study guide.

Network Simulation with Cisco CML

Read full chapter
  • A CML lab is nodes joined by links, stored as YAML
  • Node states: DEFINED, STARTED, BOOTED
  • Node definitions set the NOS and interface naming
  • External-connector bridges the lab to the outside network
  • CML is a disposable replica for pre-prod testing
  • Point a pyATS testbed at CML nodes
  • CI drives an ephemeral CML lab per run
  • Day-0 config seeds management reachability
  • CML exposes a token-authenticated REST API
  • virl2_client scripts the lab lifecycle
  • Automation uses the management IP, not the console

Unlock with Premium — includes all practice exams and the complete study guide.

Interpreting Docker Compose Files

Read full chapter
  • image pulls a prebuilt image; build builds from a Dockerfile
  • depends_on controls start order, not readiness
  • ports uses HOST:CONTAINER order
  • environment and command override image defaults
  • Services resolve each other by service name
  • Dockerfile core instructions and CMD vs ENTRYPOINT
  • A default project network connects all services
  • A service resolves only on networks it joins
  • Network aliases and multi-network services
  • Custom networks are declared at the top level
  • Named volumes vs bind mounts
  • Named volumes need a top-level declaration
  • Volume data survives down, not down -v
  • Read-only mounts protect host files
  • links are legacy and not required for discovery
  • links can create a network alias
  • The Compose Specification dropped the version key
  • restart policy keeps services alive

Unlock with Premium — includes all practice exams and the complete study guide.

Source of Truth Integration

Read full chapter
  • The SoT is the authoritative store of intended state
  • Intended vs actual state drives remediation
  • One authoritative system per data domain
  • SoT data plus templates render device config
  • NetBox is a DCIM/IPAM source of truth
  • Token auth to the NetBox API
  • NetBox dynamic inventory keeps Ansible in sync
  • NetBox webhooks trigger event-driven automation
  • Nautobot extends the NetBox SoT model
  • GraphQL fetches nested SoT data in one query
  • Golden Config operationalizes intended vs actual
  • Nautobot Jobs run automation next to the SoT

Unlock with Premium — includes all practice exams and the complete study guide.

YAML/JSON from YANG Models

Read full chapter
  • RFC 7951 defines YANG-to-JSON encoding
  • Namespace-qualified member names
  • Identityref values are module-qualified
  • JSON qualifies by module name; XML by namespace URI
  • A container maps to a JSON object
  • A list maps to a JSON array of keyed objects
  • A leaf maps to a typed scalar
  • List entries must carry their key leaf
  • YAML and JSON serialize the same structure
  • The body's top-level object matches the URL target node
  • Nesting must mirror the YANG tree exactly
  • pyang -f tree reveals the required structure

Unlock with Premium — includes all practice exams and the complete study guide.

Operations

Model-Driven Telemetry Architecture

Read full chapter

Cheat sheet

Sharp facts the exam loves — scan these before test day.

Dial-in dynamic subscriptions

In dial-in (dynamic) MDT the collector/client initiates the gRPC session to the device and creates a subscription that lives only for the duration of that session; when the client disconnects the subscription is torn down.

Trap Assuming the device (not the collector) initiates a dial-in session.

7 questions test this
Dial-out configured subscriptions

In dial-out (configured) MDT the subscription is statically configured on the device (via CLI or NETCONF) and the DEVICE initiates the connection to the receiver; it persists across sessions and reloads.

Trap Thinking the collector initiates the connection in dial-out mode.

7 questions test this
Dynamic couples to dial-in, configured to dial-out

In Cisco IOS-XE MDT the axes are coupled: dynamic subscriptions are always dial-in and non-persistent, configured subscriptions are always dial-out and persistent; 'dial-out dynamic' is not a valid combination.

Trap Choosing a 'dial-out dynamic' subscription, which does not exist.

6 questions test this
Subscription identifiers

A configured (dial-out) subscription is identified by an operator-assigned subscription-id in the device config; a dynamic (dial-in) subscription receives a server-assigned id at session establishment.

3 questions test this
gNMI runs over gRPC on HTTP/2

gNMI (gRPC Network Management Interface) runs over gRPC, which uses HTTP/2 as its transport, and TLS secures the channel; a gNMI Subscribe RPC carries the telemetry stream.

Trap Believing gNMI runs over plain TCP or SNMP.

6 questions test this
Native gRPC dial-out to a receiver

Native gRPC dial-out streams telemetry from the device to a gRPC receiver whose address and port are named in the configured subscription's receiver/destination-group.

2 questions test this
NETCONF-carried YANG-Push

MDT can also be carried over NETCONF using RFC 8639/8641 YANG-Push notifications on the NETCONF-over-SSH transport for dial-in subscriptions, not only over gRPC.

Trap Believing MDT requires gRPC exclusively.

2 questions test this
MDT replaces SNMP polling

Model-driven telemetry replaces SNMP polling: it streams YANG-modeled data and does not use SNMP traps or MIB OIDs for encoding or transport.

Trap Selecting SNMPv3 encoding or MIB OIDs as an MDT component.

2 questions test this
Periodic subscriptions

A periodic subscription streams the sensor-path data every configured period; on IOS-XE the period is expressed in centiseconds (period 3000 = 30 seconds), regardless of whether the value changed.

Trap Reading the IOS-XE period value as seconds instead of centiseconds.

7 questions test this
On-change subscriptions

An on-change subscription sends an update only when a value in the subscribed path changes, minimizing bandwidth for state that is mostly stable (e.g. interface admin/oper status).

Trap Assuming on-change streams continuously like periodic.

6 questions test this
Sensor paths anchor the data scope

A sensor-path is the YANG XPath identifying the data to stream (e.g. Cisco-IOS-XE-interfaces-oper:interfaces/interface/statistics); it defines exactly which nodes the subscription publishes.

5 questions test this
YANG-Push and subscription RFCs

RFC 8641 (YANG-Push) defines datastore subscriptions with periodic and on-change semantics; RFC 8639 defines the underlying dynamic and configured subscription mechanism.

KVGPB vs JSON encoding

gRPC dial-out MDT commonly encodes data as KVGPB (key-value Google Protocol Buffers) for compactness, while gNMI and other transports can use JSON or JSON_IETF; the subscription names the encoding.

Trap Assuming MDT only ever uses JSON encoding.

5 questions test this
Compact vs self-describing GPB

Compact GPB needs the matching .proto file to decode because it omits field keys, whereas self-describing GPB (KVGPB) embeds keys so a generic collector can decode without the .proto.

Trap Treating compact GPB and KVGPB as interchangeable at the collector.

4 questions test this
TIG collector pipeline

A common MDT collection pipeline is the TIG stack: Telegraf (the cisco_telemetry_mdt input plugin decodes the stream) -> InfluxDB (time-series store) -> Grafana (visualization).

Logging Strategy: Syslog and Webhooks

Read full chapter

Cheat sheet

Sharp facts the exam loves — scan these before test day.

Syslog severity ordering

Syslog severity ranges 0 (Emergency) to 7 (Debug); on Cisco devices 'logging trap ' sends messages at that severity AND more severe (lower number) to the syslog server.

Trap Thinking a higher severity number is more severe.

5 questions test this
Facilities and the PRI value

Syslog facility codes (0-23, e.g. local0-local7 = 16-23) categorize the source; the wire PRI value is computed as facility*8 + severity per RFC 5424.

4 questions test this
RFC 5424 message structure

An RFC 5424 syslog message has a structured header (PRI, VERSION, TIMESTAMP, HOSTNAME, APP-NAME, PROCID, MSGID) plus optional STRUCTURED-DATA and MSG, improving parseability over the legacy RFC 3164 BSD format.

Trap Confusing the legacy RFC 3164 BSD format with RFC 5424.

4 questions test this
Syslog transport options

Syslog defaults to UDP/514 (fire-and-forget, lossy); TCP/6514 with TLS (RFC 5425) provides reliable, encrypted delivery for an automation logging strategy.

Trap Assuming syslog is reliable/TCP by default.

1 question tests this
Webhooks are HTTP POST with JSON

A webhook destination is an HTTPS endpoint that receives an event via an HTTP POST carrying a JSON body; in Python the automation emits it with requests.post(url, json=payload).

Trap Assuming a webhook is delivered by HTTP GET.

5 questions test this
Authenticating webhook deliveries

Webhook receivers authenticate the sender with a shared secret in a header (e.g. an HMAC signature like X-Hub-Signature) or a bearer token so a forged POST can be rejected.

4 questions test this
Retry on failed webhook POST

Because a webhook POST can fail (receiver down, HTTP 5xx), a robust logging strategy retries with backoff and treats a non-2xx response as a failure rather than silently dropping the event.

Trap Fire-and-forget POST with no retry or status check.

1 question tests this
Choosing webhook vs syslog

Webhooks push structured JSON to application endpoints (ChatOps/incident tools such as Webex or a ticketing API); syslog streams line-oriented text to a syslog collector, so the destination is chosen per downstream consumer.

Why structured logs

Structured (JSON) logs emit each event as a machine-parsable object with named fields (timestamp, level, event, device, correlation_id), enabling reliable filtering and aggregation instead of regex-scraping free text.

4 questions test this
Emitting JSON with a formatter

In Python, structured JSON logging is achieved by attaching a JSON formatter (e.g. python-json-logger) to a logging handler so each LogRecord serializes to one JSON line.

2 questions test this
Correlation IDs for tracing

Attaching a correlation/trace id to every log line of a single automation run lets you trace one workflow across multiple devices and services when diagnosing an event later.

5 questions test this
Python logging level ordering

Python logging levels are DEBUG(10) < INFO(20) < WARNING(30) < ERROR(40) < CRITICAL(50); a logger emits records at or above its configured effective level and drops the rest.

4 questions test this
Handlers route records to destinations

Handlers route LogRecords to destinations: SysLogHandler (syslog), HTTPHandler (webhook), StreamHandler (stdout), FileHandler (file); attaching several handlers to one logger fans the same record to all of them.

3 questions test this
Prefer logging over print

Using the logging module (not print) gives per-level filtering, structured output, and multiple simultaneous destinations, whereas print writes only unlabeled text to stdout.

1 question tests this
Do not log secrets

A logging strategy must never emit secrets (tokens, passwords, private keys); redact or mask sensitive fields (e.g. the Authorization header) before the record is written to any destination.

Trap Logging full request headers including Authorization/bearer tokens.

2 questions test this

Diagnosing Automation Problems

Read full chapter
  • 401 vs 403 root causes
  • 400 vs 404 in REST/RESTCONF
  • 429 signals rate limiting
  • 5xx retryable, 4xx needs a fix
  • RESTCONF error payload
  • NETCONF rpc-error element
  • 415 Unsupported Media Type
  • 409 Conflict on POST
  • Read a traceback bottom-up
  • ConnectionError vs HTTP status
  • Connect vs read timeout
  • JSONDecodeError points to a non-JSON body
  • Isolate the failing layer first
  • CERTIFICATE_VERIFY_FAILED
  • A newly-401 call means an expired token

Unlock with Premium — includes all practice exams and the complete study guide.

Change Validation with pyATS

Read full chapter
  • Testbed YAML structure
  • device.connect() opens the session
  • Keep testbed credentials out of git
  • The os key selects plugins
  • learn() returns a structured Ops object
  • Diff(pre, post) validates a change
  • Structured diff masks volatile fields
  • learn('config') snapshots running config
  • Excluding known-dynamic keys
  • parse() returns a structured dict
  • parse() is granular, learn() is feature-wide
  • Parsers are indexed by command and os
  • AEtest script sections
  • Asserting on parsed structure
  • Job files orchestrate testscripts
  • pyats learn snapshots to files
  • pyats diff compares two snapshots
  • pyats parse from the shell
  • The end-to-end CLI validation flow

Unlock with Premium — includes all practice exams and the complete study guide.

CA-Signed TLS Certificates

Read full chapter
  • The private key never leaves the server
  • What a CSR contains
  • SAN is required, not just CN
  • Generating a CSR with openssl
  • The issuance sequence
  • ACME validates domain control
  • The CA signs with the CA private key
  • A self-signed cert is not a CSR
  • Leaf, intermediate, root chain
  • Missing intermediate breaks verification
  • The root lives in the trust store
  • PEM full-chain ordering
  • Cert must match its private key
  • Validity window and renewal
  • IOS-XE trustpoint enrollment
  • SAN must match the connected hostname

Unlock with Premium — includes all practice exams and the complete study guide.

Secure Coding Practices

Read full chapter
  • Validate with allow-lists
  • Never concatenate untrusted input
  • Validate payloads against a schema
  • Avoid eval/exec/shell with input
  • Prefer scoped short-lived tokens
  • OAuth2 client-credentials flow
  • Refresh tokens on expiry
  • Send credentials only over verified TLS
  • Disabling TLS verification (verify=False) is an anti-pattern
  • Correct remediation for CERTIFICATE_VERIFY_FAILED
  • Never hardcode or commit secrets
  • Fetch secrets from a secrets manager
  • Environment variables and their limits
  • Ansible Vault encrypts at rest
  • Base64 is not encryption

Unlock with Premium — includes all practice exams and the complete study guide.

AI in Automation

AI-Assisted Code: Benefits and Risks

Read full chapter

Cheat sheet

Sharp facts the exam loves — scan these before test day.

AI assistants accelerate authoring of automation boilerplate

AI coding assistants speed up drafting of repetitive automation code such as Ansible tasks, Python REST clients, and Jinja2 templates, reducing time-to-first-draft for common patterns.

6 questions test this
AI assistants aid API/SDK discovery and code explanation

A benefit is helping engineers discover unfamiliar SDK/API usage (for example Catalyst Center or RESTCONF payload shapes) and explain existing unfamiliar code, lowering the learning curve.

1 question tests this
The assistant is a productivity aid, not an authority

The benefit is bounded: an AI assistant is a drafting aid, not an authoritative source, so its output still requires review and testing before it can be trusted for network changes.

6 questions test this
AI assistants can scaffold consistent coding patterns

When prompted with team standards, an assistant can scaffold consistent error handling, retries, and logging across a codebase, improving maintainability.

Pasting configs/code into a cloud LLM sends data to a third party

Pasting configurations, topology, or proprietary code into a cloud LLM transmits that data to a third party that may log or train on it unless a zero-retention or enterprise no-train agreement forbids it.

Trap Assuming TLS to the API endpoint makes the prompt private; encryption in transit does not prevent server-side retention or training.

10 questions test this
Secrets embedded in prompted code are exposed

Secrets inside code that is pasted into a prompt (API keys, device passwords, SNMP community strings) are disclosed to the provider; scrub or externalize secrets before sending code to an assistant.

5 questions test this
Self-hosted models mitigate data egress at a capability cost

Running a self-hosted or on-prem model keeps prompts and code inside the organization, mitigating egress risk, at the cost of model capability and maintenance overhead.

2 questions test this
Cloud LLM use can violate data-residency requirements

Sending prompts to a cloud LLM can breach data-residency or compliance boundaries when regulated data leaves its permitted jurisdiction.

AI output may reproduce licensed training snippets

AI-generated code can reproduce snippets resembling its training data, risking license contamination (for example copyleft/GPL code) inside a proprietary codebase.

7 questions test this
Copyright status of AI-generated code is unsettled

Ownership and copyright of purely AI-generated code is legally unsettled, so organizations must set policy on whether such output may be committed and how it is attributed.

4 questions test this
Mitigate IP risk with license review of AI suggestions

The mitigation is to license-scan and review AI-suggested code before merge, treating it like any third-party dependency rather than trusted first-party code.

7 questions test this
Submitting proprietary code to train a model leaks IP

Feeding proprietary code into an external model for training or fine-tuning can leak that intellectual property into other tenants' outputs.

LLMs hallucinate non-existent APIs, modules, and YANG paths

LLMs invent plausible-looking but non-existent SDK methods, module names, or CLI/YANG paths, so generated code must be validated against real API and module documentation.

Trap Assuming code that imports and runs is correct; it may still call the wrong device semantics or a fabricated attribute.

9 questions test this
Human validation of AI code is mandatory before deployment

Human review of AI-generated automation is mandatory before it touches devices, and the engineer, not the model, remains accountable for the resulting change.

7 questions test this
AI assistants often emit insecure defaults

AI assistants frequently produce insecure defaults such as disabled TLS verification, hardcoded credentials, or overly broad permissions, which must be caught during code validation.

4 questions test this
Training cutoffs cause deprecated API suggestions

A model's training cutoff means it may suggest deprecated or removed modules and APIs (for example a removed Ansible module), so the currency of suggestions must be verified.

3 questions test this

AI Security Risks

Read full chapter

Cheat sheet

Sharp facts the exam loves — scan these before test day.

Direct prompt injection overrides the system prompt

Direct prompt injection is user-supplied input crafted to override the system prompt or guardrails, making the LLM ignore its instructions or exfiltrate data; it is OWASP LLM01:2025 Prompt Injection.

2 questions test this
Indirect prompt injection hides instructions in retrieved content

Indirect prompt injection embeds adversarial instructions in external content the agent retrieves (a wiki page, RFC, ticket, or device banner) that the model then obeys; editable ingested sources are the canonical attack surface.

Trap Sanitizing only the user's chat input while trusting retrieved documents, which is exactly where indirect injection lives.

4 questions test this
Prompt injection is mitigated by least privilege, not prompt wording

Injection cannot be eliminated by prompt wording alone; mitigations are treating model output as untrusted, least-privilege tool scoping, segregating untrusted content, and human approval for high-impact actions.

5 questions test this
Injection can push malicious config or leak secrets in a network agent

In a network automation agent, a successful injection can induce a harmful config push or cause the agent to reveal secrets through a tool call, turning a chat exploit into a device action.

7 questions test this
Sensitive Information Disclosure is OWASP LLM02:2025

OWASP LLM02:2025 Sensitive Information Disclosure covers the model revealing secrets, PII, topology, or proprietary data through its outputs.

8 questions test this
Sending network state to a third-party LLM is a disclosure vector

Feeding live configuration or network state to a third-party LLM is a disclosure vector; scope the data, redact secrets, and prefer enterprise no-train endpoints to reduce exposure.

5 questions test this
Data in prompts/fine-tuning can be memorized and resurfaced

Data included in prompts or fine-tuning can be memorized by a shared model and surfaced to other users, so regulated data should not be fed to shared models.

4 questions test this
Assume the system prompt can be extracted (LLM07:2025)

OWASP LLM07:2025 System Prompt Leakage warns that the system prompt can be extracted, so credentials and secrets must never be placed in it.

Excessive Agency is OWASP LLM06:2025

OWASP LLM06:2025 Excessive Agency is the risk that an agent with over-broad tools, permissions, or autonomy takes damaging actions from a flawed or manipulated decision.

7 questions test this
Mitigate excessive agency with least-privilege tool scoping

The mitigation is least-privilege tool design: read-only tools where possible, narrowly typed parameters, and per-action authorization for state-changing operations.

Trap Granting the agent full administrative access so it can 'handle anything', which maximizes rather than contains excessive agency.

6 questions test this
High-impact tools require a human approval gate

State-changing, high-impact tools such as config push or device reload should require explicit human approval rather than autonomous execution by the agent.

5 questions test this
Limit blast radius to contain an over-agentic action

Limiting blast radius with lab/CML targets, change windows, and RBAC-scoped service accounts contains the impact of an over-agentic or manipulated action.

OWASP LLM10:2025 Unbounded Consumption

OWASP LLM10:2025 Unbounded Consumption covers an agent loop that invokes tools or the model without bounds, exhausting compute or running up cost (denial-of-wallet); mitigations are step/loop caps, rate limiting, and per-run budget limits.

Trap Naming only prompt injection as the agent-loop risk and missing the resource-exhaustion / denial-of-wallet category.

Improper Output Handling is OWASP LLM05:2025

OWASP LLM05:2025 Improper Output Handling is passing LLM output unvalidated into downstream systems (shell, eval, device CLI, SQL), enabling injection or remote code execution.

8 questions test this
Never eval or shell-pipe raw model output

Raw model output must never be eval'd, exec'd, or piped into a shell or device; it must be validated, parameterized, and constrained before use.

Trap Trusting model output because it came from your own agent rather than an external user.

7 questions test this
Constrain tool I/O to strict schemas and allow-lists

Constraining tool inputs and outputs to strict schemas and command allow-lists prevents malformed or malicious model output from reaching devices.

4 questions test this
Supply Chain is OWASP LLM03:2025

OWASP LLM03:2025 Supply Chain covers risks from untrusted models, plugins, datasets, or dependencies, including compromised model weights and malicious MCP servers or tools.

6 questions test this
Data and Model Poisoning is OWASP LLM04:2025

OWASP LLM04:2025 Data and Model Poisoning is tampering with training, fine-tuning, or RAG data to bias or backdoor the model's outputs.

2 questions test this
A malicious MCP server/tool is a supply-chain threat

A malicious or compromised MCP server or tool can exfiltrate data or execute harmful actions, so the tools an agent may load must be vetted and pinned.

2 questions test this
Poisoned RAG sources enable injection and misinformation

Poisoned RAG sources feed both indirect prompt injection and misinformation, so write access to the agent's knowledge base must be controlled.

Building an MCP Server with FastMCP

Read full chapter
  • MCP standardizes how agents connect to tools and data
  • MCP defines host, client, and server roles
  • MCP messages are JSON-RPC 2.0 over a transport
  • MCP servers expose tools, resources, and prompts
  • Create a FastMCP server object
  • mcp.run() starts the server on stdio by default
  • FastMCP registers capabilities via decorators, not a manifest
  • A FastMCP tool returns ordinary Python objects
  • FastMCP tools may be async
  • @mcp.tool registers a function as an agent tool
  • Tool name comes from the function, description from the docstring
  • Type hints generate the tool's input schema
  • A tool can request a Context parameter
  • Example: exposing device interface status as a tool
  • @mcp.resource exposes read-only data at a URI
  • Resources are read-only data; tools are invokable actions
  • Resource URI templates bind path segments to parameters
  • @mcp.prompt registers a reusable prompt template
  • stdio is the default local transport
  • Use HTTP transport for a remote server
  • Transport is selected at run time without changing tool code

Unlock with Premium — includes all practice exams and the complete study guide.

LLM Conversational Agents

Read full chapter
  • Tools are defined to the model by name, description, and schema
  • The tool-use loop: model requests, app executes
  • Validate model-supplied tool arguments before acting
  • An MCP server becomes the agent's action surface
  • Multi-step tasks chain several tool calls
  • Grounding supplies real data to reduce hallucination
  • RAG retrieves and injects relevant context
  • Ground a network agent on the source of truth
  • RAG quality depends on retrieval freshness and integrity
  • The system prompt defines role, scope, and constraints
  • Guardrails constrain the agent independent of the prompt
  • Security controls must live in code, not only the prompt
  • Only in-context data informs the response
  • An orchestrator manages the tool-use loop
  • Conversational agents persist multi-turn message history
  • Wait for a complete tool-call block before executing
  • Return tool errors to the model and bound the loop

Unlock with Premium — includes all practice exams and the complete study guide.

Evaluating AI Recommendation Accuracy

Read full chapter
  • Test AI-generated config in CML before production
  • Verify intended state with pyATS learn and Diff
  • Deploy-then-rollback is not accuracy evaluation
  • Syntactically valid code can be semantically wrong
  • Human-in-the-loop review is the primary accuracy control
  • Accuracy is measured against ground truth
  • Two models agreeing is not proof of correctness
  • Cited sources in an AI answer must be verified
  • Overreliance falls under OWASP LLM09:2025 Misinformation
  • LLM confidence is not a calibrated correctness signal
  • Detect hallucinations by checking existence and validating config
  • AI-output accuracy needs ongoing, not one-time, review

Unlock with Premium — includes all practice exams and the complete study guide.