Repository navigation
Releases: IS4IT/midgie
Release list
midgie 0.20.0
Added
deploy --planwithout a folder writes toplan/in the deployment's own folder under$XDG_STATE_HOME/midgie, next to its rollback plans, and replaces the plan there on every run — iterating on a tree no longer leaves a plan folder per run to clean up. The run ends with the command that replays it, anddeploy <tree> --apply-planwithout a folder finds that plan from the tree.--overwritelets--planreplace the plan in a folder you named. It goes only with--plan, and only on the command line: a config file setting it is refused, asyesis.
Changed
--planrefuses a folder that holds anything but a plan — any file or subfolder midgie did not write there as part of a plan, checked before the server is contacted, with--overwritetoo. It used to accept any folder without plan files in it, so a plan could land among other files, or in a tree it was pointed at by mistake.- The documentation moved from the README to
docs/. The README is now an overview with a quick start; installing, the container image and Helm chart, the commands, removal detection, the policy file, the diff strategy, configuration, the flag reference, the safety guards and the schema each have a page of their own. Links to the README's old section anchors no longer land on those sections.
Downloads
- Standalone binary:
midgie-0.20.0.jar, below. Run it withjava -jar midgie-0.20.0.jar --help(Java 21 or later); see Installing midgie. - Container image:
is4it/midgie:0.20.0on Docker Hub, forlinux/amd64andlinux/arm64. This release builtdocker.io/is4it/midgie:0.20.0@sha256:f0ea4da598f09fe7327f3b5b846671bdc98eae05211f030edd91e35324a22f8b; pin that digest to keep the same bytes after an image-only rebuild moves the tag. See Container image and Helm chart. - Helm chart:
midgie-0.20.0.tgz, below:helm install midgie https://github.com/IS4IT/midgie/releases/download/v0.20.0/midgie-0.20.0.tgz -n midgie --create-namespace - SBOM:
midgie-0.20.0.cdx.json, below. It lists every library the JAR bundles, in CycloneDX format; Verifying a release checks it against the JAR.
midgie 0.19.0
Changed
- midgie bundles the midPoint 4.11.0 schema, and serves midPoint 4.11.x and 4.10.3 or later. One build covers both lines. 4.11 keeps 4.10's data model: its schema adds types and items, and the few it removed were deprecated since 4.8.
midgie --versionnames the range:bundled midPoint schema 4.11.0, for midPoint 4.10.3 to 4.11.x. The live modes' version check warns about a server outside that range, so a 4.11 server no longer gets the "differs from the bundled schema" warning. midPoint 4.10.0 to 4.10.2 now get it: use 0.18.5 for them, the last release built on the 4.10.5 schema. Against a 4.10 server, two cases need care:- A desired object that uses an item new in 4.11, such as
UserType/displayNameorcredentials/otp, diffs fine, and the server rejects it at deploy. - An object that still uses the eight OIDC resource-server items 4.11 removed, such as
issuerUriorjwkSetUri, no longer parses. Their replacement, thejwtandopaqueTokentoken definitions, already works on 4.10.
- A desired object that uses an item new in 4.11, such as
- Jackson comes from midPoint again. midPoint 4.11.0 brings jackson-core and jackson-databind 2.21.7 itself, the version 0.18.5 pinned, so the pin is gone.
midgie 0.18.5
Security
- Jackson is 2.21.7. The midPoint 4.10.5 schema brought jackson-core and jackson-databind 2.21.5, which have published vulnerabilities, mostly denial of service in parsing: GHSA-7hhh-6rmp-j9qf, GHSA-p6pp-m3f8-5c89, GHSA-cxp5-3px4-pw24, GHSA-wv8q-qhhj-9h54, GHSA-gx83-3vf8-gh7j, GHSA-q4xh-88c3-wmh7 and GHSA-wjgm-6hv5-3cvf. midgie now pins 2.21.7, which fixes all of them, in the JAR, the image and the SBOM. midgie parses XML, and its own JSON only in the values of its state lookup table, so the exposure was small.
midgie 0.18.4
Added
- Releases can be verified. The JAR and the Helm chart carry a SLSA build-provenance attestation, and the release attaches
midgie-<version>.cdx.json, a CycloneDX SBOM of every library the JAR bundles, attested against the JAR. The image in Docker Hub is signed with cosign and carries a provenance attestation and an SBOM of its OS packages. All of it is keyless, through Sigstore: a signature names the workflow and git ref that built the artifact. The README's new "Verifying a release" section has thegh attestation verifyandcosign verifycommands. Every build now writes the SBOM totarget/bom.json.
Changed
- A container id in a printed path follows its item's name. midgie printed
mapping/4/lifecycleState; it now printsmapping[4]/lifecycleState, the form midPoint 4.11 itself writes and the onedeploy's removal report already used for a value paired by id (inducement[3]). That covers thesummaryformat and every warning and note that names a path. The PATCH body is unchanged: its<path>elements are midPoint's own syntax. A script that reads--format summaryoutput has to expect the new form.
midgie 0.18.3
Fixed
- The removal warning in
deploy's output is one readable line. Under an object it readwarning: WARNING: this change REMOVES 1 value from the live object; - subtype (1 value), the multi-line warning of the offlinediffsquashed into one; it now readswarning: this change REMOVES 1 value from the live object: subtype ×1, the paths counted the way the "keeps live value(s)" note counts them.diffkeeps its own multi-line form.
midgie 0.18.2
Changed
- The note about an object that left the tree says when the server no longer holds it either. It asked you to delete the object yourself even when that had already been done — after a
--dry-run, or between a--planand its--apply-plan. The run now looks the object up at the end, by OID or else by type and name, and says…, and also does not exist on the server anymore.instead, dimmed like the other notes since nothing is left to do. A plan made by 0.18.1 does not record what to look the object up by, so its apply keeps the old wording, as does a run whose lookup fails.
midgie 0.18.1
Changed
-
Notes are dim and italic in a terminal.
note: …lines, and the items listed under one, no longer look like the result rows, warnings and summary they comment on. Whether to style follows the same rules as--help's colours: only when standard input and output are a terminal, never withNO_COLORset orCLICOLOR=0, and anywhere withCLICOLOR_FORCE=1— for a CI log that renders ANSI styles. Piped or redirected output is unchanged. The note naming an object that left the tree keeps full brightness. -
An object that left the tree is named at the end of the run. The note that a deleted file's object is no longer declared, and is left on the server for you to delete, came before the per-object rows and the summary, so on any real tree it scrolled out of sight — and a deploy that writes reports it only once. It is now the last thing
deployprints,--planincluded, and it names the object by type and name as well as OID —RoleType/Old Role (5a3b…)— where it gave the OID alone; so does the note that an object moved to another file.deploy --apply-planrepeats it at the end of its output too, since it is the apply that lets go of the object's record: a plan-and-apply pipeline used to name the object only in the plan job's log. A plan made by an earlier version carries no such note.
midgie 0.18.0
Changed
-
midgie needs Java 21 or later. Java 17 is no longer supported: the JAR is built for 21, the container image runs on the Temurin 21 JRE, and CI tests 21 and 25.
bin/midgierefuses an older JVM with a message naming the version it found; running the JAR directly on 17 fails withUnsupportedClassVersionError. -
Items midPoint or its operators own after creation are now written only when the object is created, with or without a policy file. midgie ships nine built-in
apply=on-createrules: taskexecutionStateandschedulingState; usercredentials,activation/administrativeStatus,activation/lockoutStatusandactivation/lockoutExpirationTimestamp; resourceadministrativeOperationalState,schema/definitionandcacheInvalidationTimestamp. Before, a redeploy resumed a task an operator had suspended, re-enabled a disabled user, unlocked a locked-out one and took a resource out of maintenance. This changes what a deploy does: a change to one of these items in the tree no longer reaches an object that already exists, and a--yesrun says nothing about it —--dry-runshowsleft alone by the policy: executionState (apply=on-create, built-in). To have midgie write one again, add a line naming the item to your--policyfile, e.g.TaskType/*/executionState apply=always; a file line wins the tie with a built-in one. The rules extend a policy file rather than being replaced by it, and there is no switch to turn them all off. An offlinediffof two files is unaffected. -
init --write-policywrites the built-in rules as active lines instead of commented-outapply=on-createsuggestions for the items the tree declares. A deploy applies them anyway, so the file still changes nothing; it now shows the whole policy in effect, with how to override each rule.ResourceType/*/schemabecameResourceType/*/schema/definition, so a resource'sschema/generationConstraintsstill deploys. The policy line names the built-ins too:midgie: policy: midgie.policy (3 rule(s), plus 9 built-in). Neither a built-in rule nor a file line restating one is reported as matching no object.
Fixed
-
An OID is checked before it becomes part of a URL. Object addresses are built by concatenation, and an OID from a tree file,
--oid, or a plan or rollback file went in as it stood:../roles/x?options=rawaddressed another collection and added a query option to the PATCH or DELETE, and an OID with a space failed with "Illegal character in path". Anything but a UUID — the only form midPoint's native repository stores — now fails that object with a message naming it, before any request is sent, and--planrefuses to write a plan file for one. -
A refused proxy URL is named without its password.
https_proxy=https://bob:S3cret@proxy:3128and every other proxy value midgie cannot use was echoed in full in the error, credentials included — and the environment is where a CI job carries them, straight into its log. The part before the host is now shown as***@. -
insecurein a config file applies to the command it names. Any key ending ininsecurecounted before any command ran, somidgie.init.insecure = trueswitched hostname verification off fordeployand every other command too. The file is now read the way picocli reads it:midgie.<command>.insecurefor that command, else bareinsecure; the same goes forproxy-user. And one of--insecure/--cacerton the command line against the other in a config file no longer refuses the run: the command line wins, with a note. -
--tracemasks password values. It printed every REST request and response body in full, so a desired password travelling as<clearValue>and the server's encrypted or hashed form went into whatever log the run wrote to — as did an error message quoting the response. The content ofclearValue,cipherValueanddigestValueis now shown as***. Plain-text values that are not recognisable as secrets can still appear, which--trace's help says. -
-o FILEis written whole and owner-only. The payload was written over the file in place, so a crash or a full disk left half a PATCH body behind, and a file that already existed kept its permissions — world-readable, say — while now holding the desired object, which may carry aclearValuepassword. It is now written to an owner-only file beside the target and renamed over it; a link is written through. -
A tree-local
.midgie.propertiesis only read from the tree. The search walked up from the working directory until it met a repository root — and outside a checkout never met one, so from/tmp/workit read a/tmp/.midgie.propertiesanyone could have left, whosepolicyorrollback-planthen applied. Outside a git checkout only the working directory's own file is read now, and a tree file that any user may change, or that belongs to another user who is not root, is ignored with a warning. -
A config file with a password that others can read is said. A
passwordorproxy-passwordin a group- or world-readablemidgie.propertiespassed without a word; each run now starts with a warning naming the file and its permissions. -
A live
diff -removes its copy of stdin when it is done. The desired object — aclearValuepassword and all — was copied tomidgie-stdin-NNN.xmlin the shared temporary directory and only removed when the JVM exited, so a run that was killed left it there. It is now written asstdin.xmlinto an owner-only directory of its own and removed as soon as the diff finishes; only a run killed outright can still leave it behind. -
A rollback that failed part way can simply be run again. The objects it had restored had new versions, which read as someone else's change, so the second run needed
--force— which turned the check off for the objects still to be restored as well. Each restored object is now marked in the plan, and runningrollbackagain sends only the rest. -
An object deployed without a recorded version needs
--forceto roll back. It was replayed as if known to be unchanged, with a warning--quiethid. Every object a rollback finds changed is now named whatever--quietasks. -
rollbacksays when it cannot check which deployment a plan belongs to. Outside a repository, or in a shallow clone, the deployment check was skipped without a word. -
Two deploys finishing in the same second keep separate rollback plans. They shared a directory, so a rollback replayed the inverses of both. Plans are named to the millisecond now, and two deployments whose names flatten to the same directory no longer rotate away or pick each other's plans.
-
An unfinished rollback plan is refused in rollback's own words, rather than with
--apply-plan's advice to re-run--plan. -
A deploy without
--yesover a tree already in sync records what it deployed. It returned before writing the tracking rows, which a--yesrun over the same tree did, so the next run judged its removals against an older revision. -
An object's last-applied files are one object whatever order they come in. A file naming the object by OID, one by name and one by both could leave two groups behind, and what one of them dropped went unseen or read as an object that left the tree.
-
A new object with an old object's name is not paired with the old one's history. The old one's values were offered for removal from the new one, and the old one's leaving went unreported.
-
Removal rules apply to the object's current name. A policy rule naming an object by the name a commit gave it missed the removals in that same commit.
-
A removal inside an entry finds that entry when the history's container ids came from another server. Paired by id, it could address the server's other entry that happened to hold the same value.
-
Writing the tracking rows survives a row another deploy moved meanwhile. The rows were addressed by the ids read at the start of the run, and one that had moved failed the whole write. They are now built from a fresh read, retried once, and a key two runs added twice is cleaned up when next written.
-
--smart-refs verifysays when it cannot verify. A search the server refused (no search rights, a 403) or that failed in transit was logged at TRACE only, and every smart reference quietly counted as a change. Each filter is now also searched once per object, not once per reference and live value. -
Several smart references in one item are no longer paired by guesswork. Under
acceptthe first live OID was taken for each filter, so with more live values than filters the one left to delete was arbitrary, and with fewer, a filter whose resolution was already there could be sent again — which midPoint 4.10 refuses, failing the whole PATCH. Underreplacesuch an item is now sent as a replace for midPoint to resolve; undermergenothing is sent for it, with a warning. -
A natural key that cannot be evaluated is said. Its entries silently fell back to pairing by id or content.
-
A policy selector keeps the spaces of an unquoted name.
RoleType/Help Deskwas read asHelp Desk. -
Two files giving different values to an item without a loaded schema are a contradiction. The union took both, turning a disagreement into two values of what may be a single-valued item. Load the schema that defines it, or declare the item in one file.
-
References midPoint maintains no longer order the deploy.
roleMembershipRef,archetypeRefand references undermetadatain an exported object counted as dependencies, ordering objects after roles they had merely been given and reporting cycles that were not there. -
What you confirm is what is sent. The writing pass reads the server again after the prompt, and an object whose change had moved in between — someone edited it while the prompt waited — was written as it now diffe...
midgie 0.17.0
Changed
-
Each object's result and its notes are printed together.
deployprinted an object's result row on stdout and its notes and warnings on stderr, before the row and each prefixed with the object's path, so telling which note belonged to which object took reading — and a CI log that captures the two streams apart could reorder them. Each object now gets one block on one stream: the result alone in the first column, and in the second the file and the object, the change, and its warnings and notes. In a terminal the second column wraps to the window width (re-read after a resize); elsewhere it is not wrapped unlessCOLUMNSis set. Per-object notes therefore now appear on stdout; notes about the run as a whole stay on stderr.--planalso shows an object's warnings, which it used to leave out.rollbackuses the same first column. -
A key left empty inside an entry no longer demotes the whole list. One
<addFocus/>without a<name>in a synchronization reaction made--equivalence autocompare everyschemaHandling/objectTypeby content, so any edit inside an object type replaced it whole — a new container id, and what the server had added inside it gone — and under merge relied on the old-form and duplicate-key safeguards to avoid a second copy. The same held for anobjectDetailsPagewith one panel lacking its<identifier>. A list that fills in its own key is now paired by it and edited in place; only the list below that leaves its key empty is compared by content.-vnames that inner list. A list that leaves its own key empty (assignment,inducement) is compared by content as before. -
A broken file in a deployed tree fails the run. A
.xmlthat is not well-formed — a merge that left its conflict markers behind — or aSchemaTypethat does not parse was skipped with a warning that--quiethid: the run exited 0 without it, and on a tracked tree its object read as removed. Both are errors now, reported before any server contact, as an unparseable object already was. -
A
--schemafile that cannot be used fails the run. One named outright that was not a schema or did not parse was warned about and skipped, so every extension item it defines diffed as raw; a missing one already failed. An unreadable--schema-dirfails too instead of reading as empty. Files inside--schema-dirin the wrong format are still skipped with a warning.
Fixed
-
Rollback rotation removes only its own run directories. After writing a net,
deploykept the newest five subdirectories of the base path and deleted every other one, recursively and through symlinks, without checking what they were. The base path can come from--rollback-planor a tree-local.midgie.properties, sorollback-plan = .deleted the tree's ownroles/,users/, … on the next deploy that wrote — letters sort after the timestamps, so the real net went first. Rotation now considers only directories with a timestamp name that hold a rollback manifest or an unfinished-plan marker, skips symlinked directories, and removes links inside a run without following them. An--app(orapp) of.or..no longer resolves the default base to the state root or the directory above it. -
An escaped
\*in a policy selector stays a literal.RoleType/\* multivalue=replace scope=full, written for a role literally named*, unescaped to the same text as the one-segment wildcard and then matched every role, full-replacing all of them. A parsed segment now remembers whether it was written as a wildcard;\*and\*\*as a whole segment match only a name that is*or**. -
apply=on-createandapply=if-absentitems are no longer deleted with their container. Only a replace of a container was checked for such items. A list compared by content changes an entry by adding its new form and deleting its old one, and the delete took the protected item along —UserType/*/assignment/activation/administrativeStatus apply=on-createdid not stop an edited assignment from losing its status. Deleting a single-valued container around the item (anactivationthe file leaves out, under--scope fullor inside a paired entry) did the same. The object is now refused instead, naming the item; giving the entry its container id in the file makes the change in place. The check runs on the whole PATCH, so a removal of a value dropped from the tree that pairs with the diff's add is caught too. Removing an entry the file no longer declares still removes it whole. -
Container ids from another server no longer pair unrelated entries. prism pairs two list values that both carry a container id by that id, under every
--equivalence,real-valueincluded, and edits one into the other. A file exported from DEV carries DEV's ids, so its<inducement id="5">re-pointed whatever PROD holds under 5 — often an entry an admin added there — and<mapping id="4"><name>fromDev</name>renamed PROD's unrelated mapping 4, undermergetoo; merge also kept the delete of a PROD entry whose id a DEV entry happened to use. midgie now checks each list's ids against the server's first: a matching id with a different filled-in natural key, a file entry the server holds under another id, or a server entry another file entry declares means the numbering is foreign, and that list's entries are paired by natural key or content instead.-vnames each such list. A file exported from the target server is unaffected, since midPoint never reuses a container id. One case remains indistinguishable: a single edited entry whose foreign id is taken, with no other entry in the list to show the mismatch. -
Merge no longer sends an empty delete beside an add. When merge kept every value a list's delete side would have removed, the emptied delete still went out as a
<delete>item delta with no value next to the add, and the summary readadd+delete. It is now left out. -
A smart reference inside an inducement or assignment is recognised. A filter-only
targetReforconstruction/resourceRefinside an entry without a container id made the whole entry differ from the server's resolved copy, and the reference-level check never saw it: every deploy deleted the resolved inducement and added one whose reference named nothing, sent withoutreevaluateSearchFilters, so midPoint stored it unresolved. Under merge a duplicate was added on every run instead. Such an entry now reads as in sync when the server's copy is its resolution; when several entries could be, it is left as a change and-vsuggests--smart-refs verify. An entry still sent whole — and a plan file holding one — goes out withreevaluateSearchFilters. -
A deploy that dies part way still leaves its rollback plan. A rejected login (401) or a lost connection in the middle of the apply ended the run before the net was written, so the objects already patched had no undo — the one case the net exists for. The plan for what was written is now saved before the error is reported.
-
Removal detection that fails for an object is reported, not read as "nothing removed". When an object's last-deployed files could not be parsed, contradicted each other, or could not be compared, detection for it ended at TRACE level and its rows moved on — so a value dropped from the tree stayed on the server for good, with a green run. Each case is now a warning that
--quietdoes not hide. An object whose old content no longer parses or whose comparison failed keeps its rows so the next run tries again; one whose files' records contradict each other (a file deployed on its own since) lets them move on, since that history would fail every run. An object that left the tree is still reported as an orphan when its old files no longer combine. -
rollbackmoves the tracking rows back with the objects. On a tracked tree a rollback restored the objects but leftmidgie-statesaying the rolled-back revision was applied. Deploying that revision again then found nothing it had dropped, and under merge the values it was meant to remove stayed beside the new ones. The rollback plan now records the rows the deploy moved, before and after, androllbackrestores them for each object it restored, leaving any row a later deploy has written since.--dry-runsays how many rows would move. -
deploy --apply-planleaves a rollback plan and records what it applied. Replaying a reviewed plan wrote neither, although every deploy that writes is documented to leave a net — so the production path had no undo, and--rollback-planwas accepted and ignored. On a tracked tree a pipeline that only ever plans and applies also never moved itsmidgie-staterows, so a value added by one plan and dropped by the next was never detected and stayed under merge.--plannow writesstate.xmlinto the plan directory with the rows an apply would write, and--apply-planwrites them for the entries it applied (leaving any row another run has moved since), builds the inverse of each body it sent, and writes the net where a deploy of that tree would.--no-rollback-planis honoured. -
An object whose inverse cannot be computed is named. A rollback plan left such an object out with a debug log line, while
deploystill reported the net. It is now named in a warning, markedunrecordedin the manifest, and reported again byrollback. -
A password source on the command line beats one from a config file. A config file's value arrives as the option's default, and
--passwordis tried before--password-envand--password-file, so apasswordin a config file outranked--password-filetyped on the command line — the documented order says the reverse. Any of the three given on the command line now comes first, whichever spelling the file uses; the proxy password likewise. -
A secret joined to a mistyped option is withheld.
--pasword=hunter2or-Phunter2printed the value i...
midgie 0.16.3
Fixed
- An edited keyed entry is replaced, not duplicated, on a tracked tree. A resource whose
schemaHandling/objectTypeheld a reaction with an unnamed<addFocus/>came out of a deploy with two object types of one kind and intent, and midPoint no longer loaded its schema.--equivalence autocompares a list by content when any key inside its entries is left empty, so the edited object type diffed to "add the new form, delete the old";merge, the default on a tracked tree, dropped that delete as a value beyond the tree, and the removal detector — which pairs the entry by itskind + intent— deleted only the items dropped from inside it. Merge now keeps the delete of a live value that carries the container id or natural key of an entry the tree declares: that value is the entry's old form. A server already holding both forms is cleaned up by the next deploy of the tree.
Added
-
A change that would hold one natural key twice is refused.
deploy, a livediffand an offlinediffproject the whole PATCH onto the live object and fail the object (exit 2) when a keyed list would end up with more values sharing one filled-in key than it has now:refusing a change that would leave schemaHandling/objectType[kind=GENERIC, intent=task] ×2 …. A duplicate the server already holds does not block. -
-vnames the listsautocompared as whole values. Per object, anote:for each list--equivalence autodid not pair by natural key, naming the key inside it that is not filled in (…/reaction/actions/addFocus does not fill in its key (name)). A change inside such a list replaces the entry whole; this was visible only in the debug log'sequivalence=field.