Command line interface

Added in version 9.0.0.

Install momotor-bundles to use the standalone commands. The same commands are available through python -m momotor.bundles. Use them when you want to build a bundle, update its metadata, or sign and verify it without writing Python code. Commands that write a bundle (build, update-meta, and sign) print the path they wrote. The verify and inspect-signatures commands write nothing. They print a report instead, with the verdict printed last for verify.

Build a bundle

Build the bundle in the current directory:

momotor-bundles build

Use a development directory, XML file, or ZIP bundle as the source:

momotor-bundles build path/to/recipe
momotor-bundles build path/to/config.xml
momotor-bundles build path/to/product.zip

The existing bundle reader loads the source. The writer collects referenced attachments and local repository directories. The output is ZIP when the bundle has attachments or --zip is set. Otherwise, the output is XML. Builds use the library’s generator option to include the library generator in root metadata. Self-test reports support the same metadata and filename rules as other bundles.

The generated filename is <name>-<bundle-type>-<version>.xml or .zip. The name comes from root metadata, then the bundle ID, then the bundle type. The version suffix is omitted when metadata has no version. Name and version components are sanitized for portable filenames.

By default, the command writes to the current working directory. Use --output-dir to keep the generated filename in another directory. Use --output to supply an exact filename, regardless of the output format:

momotor-bundles build --output-dir dist
momotor-bundles build recipe.xml --output release/recipe-bundle.zip --zip

--output and --output-dir are mutually exclusive. Missing destination directories are created. Builds cannot overwrite the source XML or archive.

For directory and ZIP sources with a custom XML filename, use --input-xml-name. Use --xml-name to change the XML member in the generated ZIP:

momotor-bundles build source.zip --input-xml-name original.xml --xml-name recipe.xml

Construction options

The command preserves the defaults and validation of FileConstructionArguments. These boolean options accept both positive and negative forms, such as --sign-files and --no-sign-files:

  • --pretty-xml

  • --sign-files

  • --optimize

  • --deduplicate

  • --deduplicate-attachments

  • --zip

  • --always-recompress

The remaining options accept values:

Option

Value

--attachment-prefix

Attachment namespace path.

--encoding

XML encoding, such as utf-8.

--xml-name

Generated ZIP’s XML member name.

--hashers

One or more algorithm names, such as sha256 sha512.

--compression

stored, deflated, bzip2, or lzma.

--compresslevel

Integer compression level accepted by the selected compression method.

--deduplicate-attachments requires --deduplicate. Directory output, dir_mode, the deprecated use_lxml argument, and generator overrides are not exposed by build.

Update metadata

Update root metadata in an XML file or ZIP bundle:

momotor-bundles update-meta recipe.xml --version 2.1
momotor-bundles update-meta recipe.zip --author 'First author' --author 'Second author'

Without output options, the input is updated in place. --output-dir uses the input’s filename, including its extension. --output uses the exact supplied filename. A destination resolving to the input also performs an in-place update:

momotor-bundles update-meta recipe.zip --version 2.1 --output-dir dist
momotor-bundles update-meta recipe.xml --name 'Release recipe' --output release/recipe.xml

At least one metadata operation is required. --name and --version accept one value each. --author, --source, --description, and --generator can be repeated. Each supplied option replaces that field’s values across all direct root <meta> blocks. The replacement values go into the first block. A root metadata block is created when needed. Nested metadata is left untouched. Omitted fields remain unchanged.

An empty string removes a field. Repeated options cannot mix empty and nonempty values. Replacement descriptions contain plain text without language or markup attributes:

momotor-bundles update-meta recipe.xml --source '' --description 'Release recipe'

Generators are preserved unless --generator replaces or removes them. --generator-name appends the library generator. With a name, it appends NAME (momotor-bundles VERSION). Existing identical generator values are not added again. --generator and --generator-name are mutually exclusive:

momotor-bundles update-meta recipe.zip --generator-name
momotor-bundles update-meta recipe.zip --generator-name 'release pipeline'
momotor-bundles update-meta recipe.zip --generator ''

For ZIP input, the command selects the single root XML member containing a Momotor bundle. Only the defined default bundle XML names at the ZIP root are candidates. Selection precedes XML parsing, and more than one candidate is always an error. Select an exact member name with --input-xml-name:

momotor-bundles update-meta bundles.zip --input-xml-name recipe.xml --version 2.1

Metadata updates use lxml without expanding XInclude or applying stylesheets. Comments, processing instructions, namespaces, whitespace, and untouched descriptions are preserved. XML serialization can change the document’s byte representation. Other ZIP members retain their compressed payloads and member metadata. Archive comments are preserved.

Both commands write to a temporary sibling file and replace the destination only after success. Failed writes leave existing files intact. Replacement preserves existing destination permissions. New build files follow the process umask. New metadata copies inherit the input’s permissions. Each successful command prints the completed output path.

CI examples

Build a recipe from its development directory and store it as a CI artifact:

build-bundle:
  script:
    - pip install momotor-bundles
    - momotor-bundles build --output-dir dist
  artifacts:
    paths:
      - dist/

Update an existing bundle’s version before publishing it:

momotor-bundles update-meta recipe.zip --version "$CI_COMMIT_TAG" --generator-name 'release pipeline'

To retain the original bundle, add --output-dir dist or an exact --output path. These commands can be adopted independently of recipe CI migration.

Public-key signing and verification

Added in version 9.0.0.

See Create a keypair for compatible OpenSSL commands.

Install momotor-bundles[signing] for cryptographic operations. Private-key passwords are read with a terminal prompt, never an argument:

momotor-bundles sign recipe.zip --private-key author.pem --output signed.zip
momotor-bundles sign signed.zip --private-key release.pem --mode add
momotor-bundles verify signed.zip --trusted-key author.pub.pem --policy any --json
momotor-bundles verify signed.zip --trusted-key author.pub.pem --policy all-present
momotor-bundles inspect-signatures signed.zip

Repeat --private-key, --trusted-key and --require-signer KEY_ID as needed. Verification uses only caller-supplied public keys. all-present requires every present record to be trusted and valid. any requires at least one; required signer IDs add independent mandatory signers. Inspection is explicitly unauthenticated. See Bundle verification for the complete trust model.

All three commands accept standalone XML files, ZIP files and directories. --input-xml-name selects the XML file or member; --xml-name is an alias on these commands. Selection is strict and ambiguous candidates are refused. Sign updates the input by default; --output or --output-dir selects a new destination. Directory signing in place updates only the selected XML:

momotor-bundles sign recipe-directory --private-key author.pem
momotor-bundles verify recipe-directory --trusted-key author.pub.pem
momotor-bundles build recipe-directory --private-key author.pem --output signed.zip

build --private-key signs the fully serialized output, including every referenced attachment, even with --no-sign-files. Signed directory exports require a new destination; direct in-place signing is supported.

update-meta refuses signed inputs unless both a matching public and private key are supplied:

momotor-bundles update-meta recipe.xml --version 2.1 \
    --trusted-key author.pub.pem --private-key author.pem

This operation verifies the supplied signer as mandatory under ANY, edits the captured document, discards old signatures and signs with the supplied key. Other unknown co-signers do not defeat ANY. Public-only, private-only, mismatched keys and invalid required signatures are refused before publication. There is no implicit signature-removal mode.

Verification exits with 0 for VERIFIED, 1 for FAILED, 2 for usage or operational errors and 3 for UNSIGNED. Successful signing and building exit with 0. --json emits the structured report. Unreferenced files are never claimed as authenticated. Missing signing dependencies are operational errors, not UNSIGNED.