Audit operator conventions against Ansible
This commit is contained in:
444
docs/roadmap/audit.md
Normal file
444
docs/roadmap/audit.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# Operator Convention Audit: ConfigKit and Ansible
|
||||
|
||||
Status: audit complete; no behavior changes proposed or authorized by this document.
|
||||
|
||||
## Scope and evidence
|
||||
|
||||
Reviewed ConfigKit revision: `2baf14d`. Comparison date: 2026-10-19.
|
||||
The [configuration contract](../config.md) owns ConfigKit behavior; this audit
|
||||
records differences, not an alternative contract or implementation plan.
|
||||
|
||||
The closest Ansible counterpart is usually YAML **variable data** loaded through
|
||||
`ansible.builtin.include_vars`, not a playbook's task language or `ansible.cfg`
|
||||
(which is INI). Where useful, comparisons explicitly identify `fileglob`, `find`,
|
||||
variable precedence, filters, or task syntax. Those mechanisms have different
|
||||
conventions even within Ansible.
|
||||
|
||||
Evidence consists of current official Ansible documentation, the versioned
|
||||
[ansible-core v2.19.0 include-vars implementation][include-source] and
|
||||
[YAML constructor][constructor], and the
|
||||
[PyYAML 6.0.2 scalar resolver][resolver]. Implementation observations below are
|
||||
identified separately from documented interfaces; they are not promises about
|
||||
every Ansible version or plugin. The `/latest/` documentation links are moving
|
||||
references. No Ansible executable is available in the development environment,
|
||||
so this is a documentation/source comparison, not a side-by-side runtime test.
|
||||
|
||||
ConfigKit's parser and import-policy implementations were inspected alongside
|
||||
their tests and maintained consumer examples. Focused YAML, import, composition,
|
||||
overlay, inheritance, version, decode, secret, and consumer tests passed on the
|
||||
reviewed tree. No code or existing policy was changed for this audit.
|
||||
|
||||
## Summary
|
||||
|
||||
| Area | Main operator surprise |
|
||||
| --- | --- |
|
||||
| YAML values | Several accepted Ansible scalar spellings are errors in ConfigKit; dates remain strings. |
|
||||
| Discovery | Directory recursion, filename filtering, missing-input handling, and wildcard syntax are not drop-in equivalents. |
|
||||
| Composition | Import overlap is a conflict, not permission for a later file to replace an earlier value. |
|
||||
| Precedence | ConfigKit recursively combines mappings across explicit tiers; Ansible normally replaces dictionary variables unless merging is requested. |
|
||||
| Reuse | ConfigKit's post-assembly sibling `extends` is neither YAML anchor reuse nor Ansible task/role inheritance. |
|
||||
| Evaluation | YAML is configuration data, not Jinja expressions, lookups, conditionals, or a task program. |
|
||||
| Secrets and inspection | Typed environment-name references and classified frozen inspection differ from Vault, lookups, and task-output controls. |
|
||||
|
||||
These differences are not automatically defects. Many follow accepted ConfigKit
|
||||
decisions, especially strict composition, predictable precedence, presence
|
||||
tracking, typed validation, and the complete-on-return lifecycle.
|
||||
|
||||
## 1. YAML parsing and scalar conventions
|
||||
|
||||
ConfigKit authority: [YAML documents](../config.md#yaml-documents),
|
||||
[scalars](../config.md#scalars), and
|
||||
[parser policy tests](../../internal/yaml/parse_test.go).
|
||||
|
||||
### Y1 — Boolean and null spellings are narrower
|
||||
|
||||
ConfigKit accepts plain lowercase `true`, `false`, and `null`, plus `~` and an
|
||||
empty mapping value for null. Unquoted `yes`, `no`, `on`, `off`, and case variants
|
||||
such as `True` or `NULL` fail rather than becoming strings. Quoting makes them
|
||||
strings, not typed booleans.
|
||||
|
||||
Ansible's YAML conventions accept additional boolean spellings; the inspected
|
||||
PyYAML resolver also recognizes mixed-case null forms. An operator copying
|
||||
`enabled: yes` must change the value to `true`, not merely quote it when the
|
||||
application expects a boolean. [Ansible YAML][ansible-yaml],
|
||||
[resolver source][resolver].
|
||||
|
||||
### Y2 — Numeric spellings and timestamp interpretation differ
|
||||
|
||||
ConfigKit uses JSON-number syntax, rejecting forms such as `010`, `0x10`,
|
||||
`1_000`, `+1`, `.5`, and `.inf`. Date/time-looking plain values remain strings.
|
||||
The inspected PyYAML resolver recognizes several non-JSON numeric forms and
|
||||
timestamps; Ansible's constructor retains timestamp construction. Do not assume
|
||||
that accepting the same YAML text produces the same scalar type.
|
||||
[Resolver source][resolver], [Ansible constructor][constructor].
|
||||
|
||||
ConfigKit also retains exact integer spelling for configured version checks,
|
||||
but ordinary typed and dynamic destinations still enforce their documented
|
||||
ranges. Ansible's Python-backed numeric data is not a guarantee that a value will
|
||||
fit a ConfigKit application's Go field.
|
||||
|
||||
### Y3 — Duplicate keys are always errors
|
||||
|
||||
ConfigKit rejects duplicate decoded mapping keys at every depth. Ansible's
|
||||
documented default is a warning; its constructor retains the last value. Ansible
|
||||
also offers error and ignore settings. A file that loads with an Ansible warning
|
||||
can therefore fail ConfigKit outright. [Duplicate-key setting][duplicate-setting],
|
||||
[constructor source][constructor].
|
||||
|
||||
### Y4 — Anchors, aliases, merge keys, and explicit tags are unavailable
|
||||
|
||||
ConfigKit rejects anchors, aliases, all explicit YAML tags, and even an ordinary
|
||||
quoted key named `<<`. Ansible documents anchor/alias/merge reuse and recognizes
|
||||
tags including `!unsafe` and `!vault`; its constructor also supports standard
|
||||
tags such as `!!str`. These files require semantic rewriting, not just moving
|
||||
them into an import directory. [Advanced syntax][advanced-syntax],
|
||||
[constructor source][constructor].
|
||||
|
||||
### Y5 — Empty variable files are not empty configuration mappings
|
||||
|
||||
ConfigKit requires one nonempty mapping document: `{}` is valid; an empty file,
|
||||
document-only marker, null root, or sequence root is not. The inspected
|
||||
`include_vars` implementation turns a null/empty parsed result into an empty
|
||||
dictionary. Explicitly use `{}` for an intentionally empty ConfigKit fragment.
|
||||
[Include-vars implementation][include-source].
|
||||
|
||||
Mapping roots themselves are **not** a divergence from normal Ansible variable
|
||||
files. Playbook sequence roots belong to a different interface. Likewise, Ansible
|
||||
has an explicit `from_yaml_all` filter for streams; that does not mean ordinary
|
||||
`include_vars` automatically accepts multiple documents. ConfigKit loading has
|
||||
no corresponding stream mode. [Variable files][variables],
|
||||
[multi-document filter guidance][filters].
|
||||
|
||||
### Y6 — Mapping keys are data strings, not Ansible variable identifiers
|
||||
|
||||
ConfigKit requires string-classified keys, quoting numeric/boolean-looking keys
|
||||
when needed. Literal dots, slashes, spaces, and numeric-looking quoted keys are
|
||||
not split into paths. Ansible distinguishes restricted top-level variable names
|
||||
from nested dictionary keys; its YAML constructor can construct non-string
|
||||
hashable keys. Porting arbitrary nested Ansible dictionary keys may require
|
||||
quoting, while imposing Ansible variable-name rules on every ConfigKit key would
|
||||
be unnecessarily restrictive. [Variable naming and dictionary access][variables],
|
||||
[constructor source][constructor].
|
||||
|
||||
## 2. Import declarations and filesystem discovery
|
||||
|
||||
ConfigKit authority: [explicit imports](../config.md#explicit-imports),
|
||||
[input destinations](../config.md#input-destinations), and
|
||||
[import internals](../internal/imports.md).
|
||||
|
||||
Defaults below are ConfigKit's library defaults. Applications can supply
|
||||
load-wide `ImportDefaults`; an explicit declaration field wins over that
|
||||
application default. Transitive declarations use the same application defaults,
|
||||
not the options authored on the declaration that selected their parent source.
|
||||
An operator must therefore check the consuming application's selected defaults.
|
||||
|
||||
| ID | ConfigKit convention | Closest Ansible convention and difference |
|
||||
| --- | --- | --- |
|
||||
| I1 | Enabled documents contain root `configkit.imports`; each declaration chooses `path`, `dir`, or `glob`. `path`/`dir` accept a string or list. | `include_vars` is a task with `file` or `dir`, normally one string; `fileglob` is a separate lookup. Ansible variable data does not recursively execute embedded include declarations. [Module][include-vars], [lookup][fileglob]. |
|
||||
| I2 | Directory discovery is shallow by default. `recursive: true` enables descendants; `depth` requires effective recursion. | `include_vars: dir` recurses by default. `find` instead defaults to `recurse: false`, with that setting overriding depth rather than making depth invalid. [Include-vars][include-vars], [find][find]. |
|
||||
| I3 | `pattern` is one or more case-sensitive basename globs; omitted means unrestricted, `[]` means no matches. | `include_vars.files_matching` is one regular expression. `find.patterns` is closer, but its documented empty/default pattern selects all rather than none. [Include-vars][include-vars], [find][find]. |
|
||||
| I4 | `exclude` uses the same basename-glob grammar. | `include_vars.ignore_files` is described as filenames; the inspected implementation actually uses suffix-anchored regex searches. `find.excludes` accepts glob/regex patterns. Do not translate fields by renaming alone. [Module][include-vars], [implementation][include-source], [find][find]. |
|
||||
| I5 | There is no extension whitelist: discovery attempts every selected filename, including `.txt` or extensionless files. | Directory `include_vars` defaults to `json`, `yaml`, and `yml`; unknown extensions fail unless configured to be ignored. This restriction does not mean an explicitly named `file` has the same filtering. [Module][include-vars], [implementation][include-source]. |
|
||||
| I6 | Missing imports are optional by default. `required: true` checks every named path, or requires a nonempty directory/glob result. | Direct `include_vars` missing-file/directory access fails. `fileglob` may return no matches, and `first_found(skip=True)` provides a different explicit absence mechanism. [Implementation][include-source], [fileglob][fileglob], [first_found][first-found]. |
|
||||
| I7 | `hidden` and `follow` default to true for discovered entries; explicit roots retain normal access. | `find` defaults both to false, and automatic `host_group_vars` ignores hidden/backup entries. The inspected `include_vars` walk follows directory links and has no equivalent hidden/follow switches; do not call ConfigKit's defaults universally unlike Ansible. [Find][find], [vars plugin][host-group-vars], [implementation][include-source]. |
|
||||
| I8 | Import paths are slash-relative to their declaring source's directory, inside its selected namespace/root. Absolute paths and URLs are invalid. | Ansible accepts absolute controller paths and uses role/play/task search contexts for relative resource lookup. Copying a role-relative name can select another file or fail in ConfigKit. [Search paths][paths], [loader source][data-loader]. |
|
||||
| I9 | A path list is a normalized set union; lexical duplicates coalesce within a declaration. Repeated admitted sources across declarations/routes fail within a strict tier. | Repeating `include_vars` tasks is allowed by the inspected implementation; no equivalent load-wide repeated-source rejection is applied there. `first_found` lists select the first hit, not all files. [Implementation][include-source], [first_found][first-found]. |
|
||||
| I10 | Source acquisition is authored/depth-first, but assembly uses the smallest dependency-ready stable source key within each strict scope. | Directory `include_vars` uses alphabetic file loading, not ConfigKit's import dependency schedule. Prefixing filenames cannot authorize ConfigKit replacement or force arbitrary dependency-violating item order. [Module][include-vars]. |
|
||||
| I11 | Optional whole-declaration empty results retain source-local `ImportSelections` evidence, not fake sources or warnings. | `include_vars` returns included file paths, rather than this optional-empty declaration record. The inspection models are not interchangeable. [Return values][include-vars]. |
|
||||
|
||||
**Depth alignment:** direct files are depth 1, and recursive depth 0 means
|
||||
unlimited subject to budgets. That is consistent with the inspected
|
||||
`include_vars` depth convention; the significant differences are recursion's
|
||||
default and whether depth is independently applicable.
|
||||
[Implementation][include-source].
|
||||
|
||||
**Empty-set behavior:** ConfigKit `path: []` succeeds even when required because
|
||||
no named target is missing. A required `dir: []` or `pattern: []` search fails
|
||||
because it selects no files. An explicit empty pattern list also overrides an
|
||||
application's nonempty default patterns. These are set meanings, not automatic
|
||||
fallback to unrestricted search.
|
||||
|
||||
### I12 — Even shell-style wildcard grammars are not identical
|
||||
|
||||
ConfigKit uses Go `path.Match`, not Python `fnmatch` or regex: character-class
|
||||
negation uses `[^a]`, whereas Python uses `[!a]`; Go backslashes escape pattern
|
||||
characters. For example, copying `[!a]*.yml` can change the selected set rather
|
||||
than producing an obvious error. Match full basenames, not regex substrings.
|
||||
[Go pattern grammar][go-match], [Python filename grammar][python-fnmatch].
|
||||
|
||||
ConfigKit's `glob` can wildcard directory components and explicitly rejects
|
||||
recursive `**`. Ansible's `fileglob` contract supports filename patterns in a
|
||||
single directory, not wildcard directory search as an interchangeable feature.
|
||||
Python glob's ordinary wildcard treatment also excludes dot-prefixed names
|
||||
unless requested by the pattern, unlike ConfigKit's default `hidden: true`.
|
||||
[Fileglob][fileglob], [Python glob][python-glob].
|
||||
|
||||
### I13 — Discovery errors and resource bounds are load failures
|
||||
|
||||
ConfigKit optionality permits absence, not malformed selected YAML, unreadable
|
||||
contributions, containment failures, active traversal cycles, or exhausted
|
||||
source/byte/node/entry budgets. The inspected Ansible directory walker logs
|
||||
`os.walk` errors through its verbosity callback rather than applying the same
|
||||
fail-the-load rule. Neither `ignore_errors` nor lookup `errors='ignore'` is an
|
||||
equivalent of ConfigKit's narrowly scoped `required: false`.
|
||||
[Implementation][include-source], [first_found behavior][first-found].
|
||||
|
||||
ConfigKit's fixed budgets have no shared, portable Ansible equivalence established
|
||||
by this audit. This is not a claim that Ansible or its parsers have no limits.
|
||||
|
||||
## 3. Combination, precedence, and inheritance
|
||||
|
||||
### C1 — Imports compose strictly rather than overriding
|
||||
|
||||
Within a main tier or one underlay group, shared mappings recurse, but overlapping
|
||||
non-mapping values conflict even when equal. Ansible variable precedence normally
|
||||
chooses a winning definition; directory `include_vars` also overwrites colliding
|
||||
keys in its accumulated results. `10-base.yml` plus `90-local.yml` is therefore
|
||||
not an override scheme for ConfigKit imports. Intentional replacement needs a
|
||||
higher ConfigKit tier. [ConfigKit strict composition](../config.md#strict-document-composition),
|
||||
[Ansible precedence][precedence], [include-vars implementation][include-source].
|
||||
|
||||
### C2 — Cross-tier mapping combination is recursive by default
|
||||
|
||||
ConfigKit retains omitted lower-tier mapping children, including when a higher
|
||||
tier supplies `{}`; other present values replace, and `[]` clears a sequence.
|
||||
Ansible's default dictionary-variable behavior is replacement, and its `combine`
|
||||
filter defaults to nonrecursive merging. ConfigKit's mapping overlay is closer
|
||||
to explicit `combine(recursive=true)` than ordinary variable reassignment.
|
||||
Ansible's global hash-merge setting is configurable and discouraged upstream;
|
||||
it is not a portable equivalence. [ConfigKit overlays](../config.md#selected-overlays),
|
||||
[hash behavior][hash-setting], [combine][combine].
|
||||
|
||||
### C3 — Registered sequence composition is not merge-by-identity
|
||||
|
||||
ConfigKit appends distinct string-ID records only at application-registered
|
||||
strict-tier paths; repeated IDs conflict. Higher-tier sequences still replace
|
||||
wholesale. Ansible `combine` offers selectable list policies, while the separate
|
||||
`community.general.lists_mergeby` filter combines records sharing an attribute.
|
||||
That optional collection filter does not describe ConfigKit's distinct-ID rule
|
||||
or Ansible's universal default. [ConfigKit registration](../config.md#strict-document-composition),
|
||||
[combine][combine], [lists_mergeby][lists-mergeby].
|
||||
|
||||
### C4 — The precedence model and lifetime are different
|
||||
|
||||
ConfigKit loads application defaults, ordered underlays, main, selected overlay,
|
||||
and explicit CLI values into one completed result. It supplies no general
|
||||
environment-variable overlay. Ansible has host/play/task scopes and runtime
|
||||
variable definitions; ordinary command-line options are not generally highest
|
||||
priority, while `-e` extra variables are. Environment also configures Ansible
|
||||
itself. Do not equate every application flag with Ansible's ordinary CLI category.
|
||||
[ConfigKit layered loading](../config.md#layered-loading),
|
||||
[Ansible precedence][precedence].
|
||||
|
||||
ConfigKit rejects duplicate or overlapping explicit override records rather
|
||||
than providing a last-argument-wins channel. It accepts typed values supplied by
|
||||
the application; it does not define an Ansible-style `key=value` parser.
|
||||
Ansible extra-vars `key=value` values are strings; JSON/YAML forms preserve
|
||||
other types. [ConfigKit overrides](../config.md#explicit-cli-overrides),
|
||||
[Ansible extra vars][variables].
|
||||
|
||||
### C5 — Defaults depend on presence, not truthiness
|
||||
|
||||
ConfigKit preserves explicit false, zero, empty text/list, and allowed null;
|
||||
omission retains defaults. Null is not universally legal: application Go scalar
|
||||
and struct fields reject it, while supported nullable fields accept it. Ansible
|
||||
can distinguish undefined from false/null too. Its ordinary Jinja `default`
|
||||
filter handles undefined, while `default(value, true)` additionally treats falsey
|
||||
values as needing replacement; `omit` is a separate task-argument mechanism.
|
||||
That opt-in truthiness behavior has no ConfigKit YAML equivalent.
|
||||
[ConfigKit decoding](../config.md#defaults-and-typed-decoding),
|
||||
[Ansible default and omit guidance][filters].
|
||||
|
||||
### C6 — `extends` is post-assembly sibling inheritance
|
||||
|
||||
ConfigKit resolves an exact immediate sibling mapping after all tiers combine;
|
||||
the child recursively overlays its parent. `extends: null` cancels a relationship,
|
||||
and enclosing inheritance precedes nested destination-local resolution. All
|
||||
effective relationships are resolved, not just an application-selected preset.
|
||||
|
||||
Ansible YAML anchors/`<<` reuse nodes within one document during parsing, and
|
||||
YAML merge does not recursively combine an already-present nested child mapping.
|
||||
Ansible play/block/task keyword inheritance is another distinct mechanism.
|
||||
Neither is a drop-in equivalent of ConfigKit `extends`; explicit Ansible
|
||||
recursive `combine` expressions can approximate parts of the value operation.
|
||||
[ConfigKit inheritance](../config.md#sibling-inheritance),
|
||||
[Ansible advanced syntax][advanced-syntax], [YAML merge definition][yaml-merge],
|
||||
[keyword inheritance][precedence], [combine][combine].
|
||||
|
||||
## 4. Structural controls, evaluation, and schema
|
||||
|
||||
### S1 — Reserved data keys and destination syntax differ
|
||||
|
||||
ConfigKit reserves `configkit` for root directives and rejects it below the root;
|
||||
with imports disabled it is still not ordinary application data. `extends` is
|
||||
structural input, and quoting a key does not bypass either control. Ansible
|
||||
variable dictionaries do not give these two names ConfigKit's structural meaning.
|
||||
Do not confuse this with Ansible's own magic-variable and playbook-keyword rules.
|
||||
[ConfigKit imports](../config.md#explicit-imports),
|
||||
[inheritance](../config.md#sibling-inheritance), [Ansible variable rules][variables].
|
||||
|
||||
Import `destination: [catalog, entries]` means literal mapping segments relative
|
||||
to the immediate importer; `[]` adds none. `placement: sequence-item` builds a
|
||||
record in that destination's sequence, with a local helper scope. Ansible's
|
||||
`include_vars.name` wraps data under one variable, not this relative mount/item
|
||||
model; dots are not a substitute for ConfigKit segment lists.
|
||||
[ConfigKit destinations](../config.md#input-destinations),
|
||||
[Ansible include-vars namespace][include-vars].
|
||||
|
||||
### S2 — Jinja, conditional includes, and lookups are not evaluated
|
||||
|
||||
In ConfigKit, `"{{ value }}"`, `"{{ lookup('env', 'TOKEN') }}"`, and `${TOKEN}`
|
||||
are ordinary strings unless application code gives them domain meaning; no
|
||||
generic template pass exists. `when`, `loop`, `tags`, and `ignore_errors` are
|
||||
not import-declaration controls. Ansible supports Jinja references/lookups and
|
||||
task-level conditionals and loops. Configuration must be translated structurally
|
||||
or handled by deliberate application resolution, not presumed executable.
|
||||
[ConfigKit resolution](../config.md#recorded-application-resolution),
|
||||
[Ansible variables][variables], [task keywords][keywords], [env lookup][env].
|
||||
|
||||
### S3 — Final typed validation and version ownership are library boundaries
|
||||
|
||||
ConfigKit strictly decodes the assembled result against the application's Go
|
||||
shape: unknown struct fields and incompatible values fail; dynamic maps leave
|
||||
domain-key validation to the application. Its configured version rule accepts
|
||||
string/integer declarations, can consume non-main headers, and protects the main
|
||||
version path from imports/upper tiers/inheritance. None of those policies should
|
||||
be inferred from the word `version` alone.
|
||||
|
||||
Ansible variable-file loading is not validation against one final application
|
||||
schema; validation occurs at other boundaries, including module/role argument
|
||||
specifications. A variable named `version` is not by itself a ConfigKit-style
|
||||
protected, consumed header. [ConfigKit versions](../config.md#shared-source-version-checks),
|
||||
[typed decoding](../config.md#defaults-and-typed-decoding),
|
||||
[Ansible role validation][roles], [include-vars data loading][include-source].
|
||||
|
||||
ConfigKit's integer-version-to-string exception is specific to that configured
|
||||
path. It does not establish general Ansible-like filter coercion elsewhere.
|
||||
[Ansible type conversion filters][filters].
|
||||
|
||||
For a field typed as `time.Duration`, ConfigKit requires a duration string such
|
||||
as `5s`, not an integer count of seconds. Ansible duration arguments are module
|
||||
specific; for example, `wait_for.timeout` uses integer seconds. Translate the
|
||||
particular field's representation rather than assuming one shared duration type.
|
||||
[ConfigKit decoding](../config.md#defaults-and-typed-decoding),
|
||||
[Ansible wait_for][wait-for].
|
||||
|
||||
### S4 — Overlay selection and module objects are ConfigKit/application conventions
|
||||
|
||||
A selected ConfigKit overlay uses exactly `overlays/<name>.yml`; empty or exact
|
||||
`default` means no overlay. There is no extension fallback or stack. Ansible's
|
||||
inventory/role variable directories are different selection and precedence
|
||||
mechanisms, not this named overlay convention.
|
||||
[ConfigKit overlays](../config.md#selected-overlays), [Ansible vars plugin][host-group-vars],
|
||||
[roles][roles].
|
||||
|
||||
The canonical module-object guidance uses an explicit identifier and options
|
||||
mapping; individual field names belong to applications. Ansible tasks instead
|
||||
name an action/module or use `action`/`args`, with task keywords alongside it.
|
||||
A generic ConfigKit configuration object is not an Ansible task, and ConfigKit
|
||||
does not provide an Ansible module registry or execute a module-named mapping.
|
||||
[ConfigKit module guidance](../config.md#canonical-module-options),
|
||||
[Ansible task syntax][playbooks], [keywords][keywords].
|
||||
|
||||
## 5. Secrets, resources, and inspection
|
||||
|
||||
### O1 — A typed secret field contains an environment name
|
||||
|
||||
For a ConfigKit `Secret` slot, `api_key: SERVICE_TOKEN` is a reference to one
|
||||
nonempty effective environment value; ordinary string slots do not gain that
|
||||
behavior. Missing/unset/empty required secrets fail. Ansible uses explicit env
|
||||
lookups or other secret providers; its env lookup defaults to an empty string
|
||||
for undefined names unless configured otherwise. These are different missing-value
|
||||
and evaluation conventions. [ConfigKit secrets](../config.md#typed-secret-references),
|
||||
[Ansible env lookup][env].
|
||||
|
||||
Vault-encrypted files or `!vault` values are not ConfigKit inputs to decrypt.
|
||||
Ansible Vault protects stored content and supplies decryption through Ansible;
|
||||
ConfigKit's typed reference deliberately keeps credential bytes out of YAML
|
||||
composition/history. Its separate secrets-directory bootstrap is an application
|
||||
startup operation, not another YAML include or a Vault equivalent.
|
||||
[ConfigKit bootstrap](../config.md#explicit-secrets-directory-bootstrap),
|
||||
[Ansible Vault][vault].
|
||||
|
||||
### O2 — Redaction and serialization are not task `no_log`
|
||||
|
||||
ConfigKit has application-classified paths and typed secret references, with
|
||||
frozen redacted effective/explanation output; there is no YAML `no_log` control
|
||||
or unredacted renderer option. Ansible `no_log` controls task output and does not
|
||||
make every debug operation safe. Vault encryption and `!unsafe` also have
|
||||
different purposes; neither is a synonym for ConfigKit classification.
|
||||
[ConfigKit inspection](../config.md#secret-classification-and-effective-rendering),
|
||||
[Ansible logging][logging], [advanced syntax][advanced-syntax].
|
||||
|
||||
ConfigKit effective YAML uses a fixed deterministic layout and may not be
|
||||
reloadable after redaction. Ansible `to_nice_yaml` exposes formatting options
|
||||
such as indentation and key sorting; it is serialization, not ConfigKit's frozen
|
||||
safe-inspection contract. Do not use either output interchangeably without
|
||||
checking the consumer's required representation. [Ansible YAML filter][nice-yaml].
|
||||
|
||||
### O3 — Resource paths are passive data, not generic Ansible file lookup
|
||||
|
||||
ConfigKit retains the declaring source's resource context, including through
|
||||
inheritance; applications explicitly open resource-valued fields. It does not
|
||||
automatically resolve every string that resembles a path. Ansible file resources
|
||||
are interpreted by their specific module/lookup and controller/remote search
|
||||
context. These differ from ConfigKit import paths as well as from arbitrary
|
||||
application data. [ConfigKit resource contexts](../config.md#source-resource-contexts),
|
||||
[Ansible path contexts][paths].
|
||||
|
||||
## Assessment and follow-up
|
||||
|
||||
The most plausible convention-alignment discussion is discovery: recursion,
|
||||
filter names/grammar, filename defaults, absence handling, and hidden/link
|
||||
defaults. First choose the intended comparison (`include_vars`, `fileglob`, or
|
||||
`find`); copying pieces from each would not create one coherent Ansible convention.
|
||||
|
||||
Preserve ConfigKit's accepted composition, presence, lifecycle, and provenance
|
||||
decisions unless the maintainer explicitly chooses to change them. YAML scalar
|
||||
and reuse differences likewise reflect an owned parsing policy, not an accidental
|
||||
failure to inherit upstream YAML behavior. Documenting a difference does not
|
||||
authorize adding a compatibility mode, a new restriction, or an implementation.
|
||||
|
||||
Immediate operator guidance from the audit is to review imported files for
|
||||
overlapping values, use explicit directory filters/requiredness when intended,
|
||||
translate regex/Python patterns rather than copying them, and replace Ansible
|
||||
tags/templates/anchors with supported application data and ConfigKit mechanisms.
|
||||
|
||||
Validation for this documentation pass: focused ConfigKit YAML and engine tests,
|
||||
maintained consumer examples, local documentation links, and whitespace checks.
|
||||
External sources were reviewed online; no Ansible installation or application
|
||||
consumer dependencies were changed. This is not an exhaustive audit of Ansible's
|
||||
third-party plugin ecosystem or a claim that its behavior is uniform across
|
||||
versions and application-specific modules.
|
||||
|
||||
[ansible-yaml]: https://docs.ansible.com/projects/ansible/latest/reference_appendices/YAMLSyntax.html
|
||||
[advanced-syntax]: https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_advanced_syntax.html
|
||||
[include-vars]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/include_vars_module.html
|
||||
[include-source]: https://github.com/ansible/ansible/blob/v2.19.0/lib/ansible/plugins/action/include_vars.py
|
||||
[constructor]: https://github.com/ansible/ansible/blob/v2.19.0/lib/ansible/_internal/_yaml/_constructor.py
|
||||
[resolver]: https://github.com/yaml/pyyaml/blob/6.0.2/lib/yaml/resolver.py
|
||||
[data-loader]: https://github.com/ansible/ansible/blob/v2.19.0/lib/ansible/parsing/dataloader.py
|
||||
[duplicate-setting]: https://docs.ansible.com/projects/ansible/latest/reference_appendices/config.html#duplicate-yaml-dict-key
|
||||
[hash-setting]: https://docs.ansible.com/projects/ansible/latest/reference_appendices/config.html#default-hash-behaviour
|
||||
[fileglob]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/fileglob_lookup.html
|
||||
[first-found]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/first_found_lookup.html
|
||||
[find]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/find_module.html
|
||||
[host-group-vars]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/host_group_vars_vars.html
|
||||
[paths]: https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbook_pathing.html
|
||||
[go-match]: https://pkg.go.dev/path#Match
|
||||
[python-fnmatch]: https://docs.python.org/3/library/fnmatch.html
|
||||
[python-glob]: https://docs.python.org/3/library/glob.html
|
||||
[precedence]: https://docs.ansible.com/projects/ansible/latest/reference_appendices/general_precedence.html
|
||||
[variables]: https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_variables.html
|
||||
[filters]: https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_filters.html
|
||||
[combine]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/combine_filter.html
|
||||
[lists-mergeby]: https://docs.ansible.com/projects/ansible/latest/collections/community/general/lists_mergeby_filter.html
|
||||
[yaml-merge]: https://yaml.org/type/merge.html
|
||||
[roles]: https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_reuse_roles.html
|
||||
[keywords]: https://docs.ansible.com/projects/ansible/latest/reference_appendices/playbooks_keywords.html
|
||||
[playbooks]: https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_intro.html
|
||||
[env]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/env_lookup.html
|
||||
[vault]: https://docs.ansible.com/projects/ansible/latest/vault_guide/vault_encrypting_content.html
|
||||
[logging]: https://docs.ansible.com/projects/ansible/latest/reference_appendices/logging.html
|
||||
[nice-yaml]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/to_nice_yaml_filter.html
|
||||
[wait-for]: https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/wait_for_module.html
|
||||
Reference in New Issue
Block a user