Skip to content

feat(rpm-repos): TOML-driven RPM repo definitions for mock and kiwi#156

Draft
reubeno wants to merge 3 commits intomicrosoft:mainfrom
reubeno:feat/toml-driven-rpm-repos
Draft

feat(rpm-repos): TOML-driven RPM repo definitions for mock and kiwi#156
reubeno wants to merge 3 commits intomicrosoft:mainfrom
reubeno:feat/toml-driven-rpm-repos

Conversation

@reubeno
Copy link
Copy Markdown
Member

@reubeno reubeno commented May 5, 2026

Define RPM repositories once under [resources.rpm-repos.NAME] in the distro TOML, then select them per-distro-version via [distro.versions.X.inputs.rpm-build] and inputs.image-build. azldev projects them into the mock chroot config (for component builds) and into kiwi --add-repo arguments (for image builds), removing the need to hard-code repo URLs in mock .tpl files or in .kiwi files for local builds.

Schema (internal/projectconfig/resources.go):

  • New [resources] top-level table; rpm-repos is keyed by repo name
  • Per-repo fields: description, type ('rpm-md' for now), base-uri OR metalink (mutually exclusive), disable-gpg-check (zero value = GPG enabled, the safe default), gpg-key, arches
  • Repo names: ^[A-Za-z0-9][A-Za-z0-9_.:-]*$ (projected verbatim into dnf section headers and kiwi --add-repo args)
  • URI scheme allowlist: http/https for base-uri/metalink; http/https/file for gpg-key; bare gpg-key paths resolved relative to the defining TOML file at load time
  • Reject control characters (CR/LF/NUL/U+2028/U+2029) in projected string fields
  • Cross-section: reject local gpg-key paths from inputs.rpm-build (mock evaluates URI inside chroot where host paths are invisible)
  • JSON schema mirrors these constraints (propertyNames + URI patterns) so editors can flag invalid TOML at edit time

Mock RPM build (core/mockconfig/prepare.go):

  • New mockconfig package stages a per-build configdir in the project work dir and emits a site-defaults.cfg fragment that sets config_opts['azl_repos'] to a list of dicts derived from the selected resources. The mock .cfg template iterates this list to build dnf.conf, keeping most repo logic in the template.
  • Repo dicts are emitted via json.Marshal-based pyRepr (every JSON string literal is a valid Python string literal), with explicit U+2028/U+2029 backstop
  • Honors per-repo arches filter against the mock chroot's target arch (amd64/arm64 mapped to x86_64/aarch64)
  • Empty inputs.rpm-build is informational (legitimate for hand- maintained stage1 templates); only warns when arch filter empties the list

KIWI image build (cmds/image/build.go):

  • addConfiguredImageBuildRepos walks inputs.image-build, applies the arches filter against the build target's arch, and calls kiwi.AddRemoteRepo. Errors out (rather than silently producing a no-repo image) if every configured repo is filtered out.
  • disable-gpg-check maps to BOTH DisablePackageGPGCheck and DisableRepoGPGCheck (mirrors dnf's gpgcheck=0 semantics)
  • gpg-key is threaded into kiwi SigningKeys

Define RPM repositories once under [resources.rpm-repos.NAME] in the
distro TOML, then select them per-distro-version via
[distro.versions.X.inputs.rpm-build] and inputs.image-build. azldev
projects them into the mock chroot config (for component builds) and
into kiwi --add-repo arguments (for image builds), removing the need
to hard-code repo URLs in mock .tpl files or in .kiwi files for local
builds.

Schema (internal/projectconfig/resources.go):
- New [resources] top-level table; rpm-repos is keyed by repo name
- Per-repo fields: description, type ('rpm-md' for now), base-uri OR
  metalink (mutually exclusive), disable-gpg-check (zero value =
  GPG enabled, the safe default), gpg-key, arches
- Repo names: ^[A-Za-z0-9][A-Za-z0-9_.:-]*$ (projected verbatim into
  dnf section headers and kiwi --add-repo args)
- URI scheme allowlist: http/https for base-uri/metalink;
  http/https/file for gpg-key; bare gpg-key paths resolved relative
  to the defining TOML file at load time
- Reject control characters (CR/LF/NUL/U+2028/U+2029) in projected
  string fields
- Cross-section: reject local gpg-key paths from inputs.rpm-build
  (mock evaluates URI inside chroot where host paths are invisible)
- JSON schema mirrors these constraints (propertyNames + URI patterns)
  so editors can flag invalid TOML at edit time

Mock RPM build (core/mockconfig/prepare.go):
- New mockconfig package stages a per-build configdir in the project
  work dir and emits a site-defaults.cfg fragment that sets
  config_opts['azl_repos'] to a list of dicts derived from the
  selected resources. The mock .cfg template iterates this list to
  build dnf.conf, keeping most repo logic in the template.
- Repo dicts are emitted via json.Marshal-based pyRepr (every JSON
  string literal is a valid Python string literal), with explicit
  U+2028/U+2029 backstop
- Honors per-repo arches filter against the mock chroot's target arch
  (amd64/arm64 mapped to x86_64/aarch64)
- Empty inputs.rpm-build is informational (legitimate for hand-
  maintained stage1 templates); only warns when arch filter empties
  the list

KIWI image build (cmds/image/build.go):
- addConfiguredImageBuildRepos walks inputs.image-build, applies the
  arches filter against the build target's arch, and calls
  kiwi.AddRemoteRepo. Errors out (rather than silently producing a
  no-repo image) if every configured repo is filtered out.
- disable-gpg-check maps to BOTH DisablePackageGPGCheck and
  DisableRepoGPGCheck (mirrors dnf's gpgcheck=0 semantics)
- gpg-key is threaded into kiwi SigningKeys

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 5, 2026 18:44
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds TOML-driven, reusable RPM repository definitions under resources.rpm-repos and wires them into both mock (RPM builds) and kiwi (image builds), reducing hard-coded repo URLs in template/config files.

Changes:

  • Introduces ResourcesConfig + RpmRepoResource (with validation, merge semantics, and path absolutization) and connects them to distro.versions.*.inputs selectors.
  • Generates a per-build mock --configdir with a site-defaults.cfg fragment (config_opts['azl_repos']) derived from configured repos.
  • Injects inputs.image-build repos into kiwi via --add-repo, including arches filtering and GPG-check mapping; updates schema + snapshots and adds tests.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
schemas/azldev.schema.json Adds schema for resources + per-version inputs and RPM repo resource objects.
scenario/snapshots/TestSnapshots_config_generate-schema_stdout_1.snap Updates schema snapshot output to reflect new schema nodes.
scenario/snapshots/TestSnapshotsContainer_config_generate-schema_stdout_1.snap Updates container schema snapshot output to reflect new schema nodes.
internal/projectconfig/resources.go Implements resources model, validation, schema extension, and path resolution for gpg-key.
internal/projectconfig/resources_test.go Adds unit tests for repo validation, path absolutization, merge semantics, and helpers.
internal/projectconfig/project.go Validates repo resources and per-version input references at config load time.
internal/projectconfig/loader.go Merges resources across config files and resolves relative gpg-key paths at load time.
internal/projectconfig/distro.go Adds DistroVersionInputs to select repos for rpm-build and image-build.
internal/projectconfig/configfile.go Adds resources section to per-file config structure.
internal/app/azldev/core/testutils/testenv.go Seeds test env with a sample repo resource and rpm-build inputs.
internal/app/azldev/core/mockconfig/prepare.go New mock config staging + site-defaults.cfg generation + repo filtering + pyRepr.
internal/app/azldev/core/mockconfig/prepare_test.go Tests mock site-defaults.cfg generation and staging behavior.
internal/app/azldev/core/buildenvfactory/factory.go Routes mock builds through staged per-build mock config generated from TOML inputs.
internal/app/azldev/cmds/image/build.go Injects configured image-build repos into kiwi runner and maps GPG settings/signing keys.
internal/app/azldev/cmds/image/build_repos_internal_test.go Tests kiwi --add-repo argument construction from repo resources.
internal/app/azldev/cmds/component/render.go Uses staged mock config for mock processor creation.
internal/app/azldev/cmds/advanced/mock_test.go Updates test config to include repo resources + inputs for rpm builds.

Comment on lines +913 to +926
"base-uri": {
"type": "string",
"pattern": "^https?://[^\\s]+$",
"format": "uri",
"title": "Base URI",
"description": "Repository base URI (dnf baseurl). Mutually exclusive with metalink. Must be an http(s) URL."
},
"metalink": {
"type": "string",
"pattern": "^https?://[^\\s]+$",
"format": "uri",
"title": "Metalink",
"description": "Repository metalink URL. Mutually exclusive with base-uri. Must be an http(s) URL."
},
Comment on lines +932 to +937
"gpg-key": {
"type": "string",
"pattern": "^\\S+$",
"title": "GPG key",
"description": "Path or URI to the GPG key file. Bare paths are resolved relative to the defining TOML file. Accepted URI schemes: http"
},
Comment thread internal/projectconfig/resources.go Outdated
Comment on lines +278 to +290
u, err := url.Parse(raw)
if err != nil {
return fmt.Errorf("rpm-repo %#q `%s` is not a valid URI: %w", repoName, field, err)
}

switch strings.ToLower(u.Scheme) {
case "http", "https":
return nil
case "":
return fmt.Errorf("rpm-repo %#q `%s` is missing a scheme; expected http(s)://...", repoName, field)
default:
return fmt.Errorf("rpm-repo %#q `%s` uses unsupported scheme %q; only http and https are accepted", repoName, field, u.Scheme)
}
Comment thread internal/projectconfig/resources.go Outdated
Comment on lines +313 to +314
case "http", "https", "file":
return nil
Comment on lines +295 to +301
repoNames := distroVerDef.Inputs.ImageBuild
if len(repoNames) == 0 {
return fmt.Errorf(
"no rpm repos configured for image-build on the active distro version; " +
"define inputs.image-build under the appropriate [distros.X.versions.Y]",
)
}
Copilot AI added a commit to reubeno/azure-linux-dev-tools that referenced this pull request May 5, 2026
Copilot AI added a commit to reubeno/azure-linux-dev-tools that referenced this pull request May 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants