Skip to content

CFEngine Build modules, and blocks for their promise types - #57

Merged
aleksandrychev merged 23 commits into
cfengine:mainfrom
aleksandrychev:modules-panel
Oct 16, 2026
Merged

aleksandrychev merged 23 commits into
cfengine:mainfrom
aleksandrychev:modules-panel

Conversation

@aleksandrychev

Copy link
Copy Markdown
Collaborator

Adds modules from the CFEngine Build index (build.cfengine.com) to the builder, and blocks for the promise types they provide.

Modules

  • A VS Code-style activity bar switches the side bar between Blocks and files and a new Modules view: search (every word, old names too), tag chips, Supported only, "In this project" and "All modules".
  • A module's page opens over the canvas, like on build.cfengine.com: README, links, maintainer, downloads, versions, tags. The details come from build.cfengine.com's own js/modules.json (what Mission Portal uses). The README becomes plain data rendered as React elements, never as HTML. Only GitHub images load (CSP img-src).
  • Adding and removing modules, and answering their input (the Input tab, in Mission Portal's layout), are undoable project edits. Saving runs cfbs add / cfbs remove before writing anything else, and writes <module>/input.json. Modules run before the project's own policy. Policy sets only.
  • Test runs build the project with its modules and their input.

Promise-type blocks

  • Git Checkout, Systemd Unit, HTTP Request and Run Ansible Playbook, plus Custom Promise for any module's promise type (name = value attribute rows).
  • Adding one adds its module. The module can't be removed while a block uses it.
  • Notes on these become # Note: lines: promise modules refuse comment.
  • The blocks advise installing python3, with buttons to add an Install python3 block before them or to ignore the advice for the project.
  • The demo downloads the CFEngine logo with an HTTP Request and shows it on its landing page.

AI agents (MCP)

  • New tools: search_modules, get_module, add_module, set_module_input, remove_module.
  • The guide covers modules and these blocks.
  • Two field tests with an agent without repository access built a project with modules and promise-type blocks; the second passed on a Debian 12 test host.

Tests

  • Unit, component and main-process tests.
  • An offline integration test: real sidecar and cfbs, with a local git module listed by a custom index.
  • An offline e2e journey on fixture data (CFPB_MODULE_DATA, development builds only).
  • Opt-in network and Docker journeys. The Docker one checks the demo's logo is served.

🤖 Generated with Claude Code

aleksandrychev and others added 23 commits October 16, 2026 20:10
…r pages

An activity bar on the left switches the side bar between Blocks and files
and Modules. Modules lists the CFEngine Build index (searched, filtered by
tag), and a module's page shows its README, links, stats and versions from
build.cfengine.com's module data. Adding a module isn't saved yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
…dule page

Saving runs cfbs add / remove for the modules gained or dropped since the
last save, before writing anything else, and writes each module's answers
to <name>/input.json. Opening a project reads them back. Adding, removing
and answering are undoable project edits.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
…ok blocks

They use the git, systemd, http and ansible promise types from CFEngine
Build modules: adding one of these blocks adds its module to the project,
which can't be removed while a block uses it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
… type

It takes the promise type, the promiser and name = value attribute rows,
each compiled to a string or a list of quoted strings, and adds the
promise type's module to the project like the other module blocks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
…ette

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
The module comes from a local git repository listed by a custom index, so
cfbs adds and builds it without the network.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
…s, saving

Development builds read the module index and details from the folder
CFPB_MODULE_DATA names, so the journey runs offline on e2e/modules/.
Saving with cfbs downloads, so that one is opt-in with CFPB_NETWORK_TESTS.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
… input

They built only masterfiles and the builder's own policy, so a project
using modules or promise-type blocks failed with Undefined promise type.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
Promise modules refuse it: Unknown attribute 'comment' for git promise.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
Without one the git module clones --branch HEAD, which git refuses.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
name => "value", with a trailing comma, compiled to a value starting
with > and wrapped in escaped quotes; a quoted value is now the text
inside the quotes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
set_module_input says what it stored and which questions are left, and
get_module's README text keeps a table's cells as a | b instead of runs
of tabs and line breaks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
…it names

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
The project overview lists the dependencies cfbs adds on save for a
block's module; the note, Custom Promise and test environment texts say
what really happens.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
…s it

The advice shows in Properties and get_warnings until an Install Package
block brings python3; the button adds one above the block with an arrow
into it, as one undo step.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
…t under it

Ignoring is saved with the project (dismissed_advice in project.json) and
hides the advice in Properties and get_warnings; undo brings it back. The
advice shows without its icon, which took the text's width.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
The landing page shows the logo, which an http promise (promise-type-http)
fetches into the web root at most once a day, after python3 is installed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Ihor Aleksandrychiev <ihor.aleksandrychiev@northern.tech>
@aleksandrychev
aleksandrychev merged commit 1e27269 into cfengine:main Oct 16, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant