Remove the completed operator convention audit
This commit is contained in:
@@ -1,444 +0,0 @@
|
|||||||
# 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