Skip to content

Release v0.6.1 - #30

Merged
jbrazda merged 53 commits into
mainfrom
dev
Oct 24, 2026
Merged

jbrazda merged 53 commits into
mainfrom
dev

Conversation

@jbrazda

@jbrazda jbrazda commented Oct 24, 2026

Copy link
Copy Markdown
Owner

Patch release v0.6.1: agent configuration and service fixes.

Merge method: fast-forward (git push origin dev:main), keeping every commit.

Fixed

  • agent configs set, agent configs edit and agent rename failed with
    HTTP 500 after an Administrator UI change. The agent form's property rows
    are now sent in the configFormJson field, as the UI sends them.
  • agent configs no longer reports values that differ from the default only
    in line endings or whitespace as overridden. Setting such a value, or
    resetting a property that is not overridden, is no longer shown as a
    change.
  • agent restart --blocking and agent start --blocking timed out while
    Process Server was still starting. --max-wait-time now defaults to 1200
    seconds (20 minutes) for start and restart (stop keeps 300), poll
    lines label subStates (-1 - Initializing, 2 - Starting,
    0 - Operational), and a timeout reports the last state seen.
  • agent details --full showed every property as not customized, because the
    API's customized flag only marks custom properties. The CUSTOMIZED
    column is replaced by OVERRIDDEN (custom, yes or empty), computed from
    value and default as in agent configs get, and JSON/YAML output adds an
    overridden field.

🤖 Generated with Claude Code

- role get: look up by --id or --name via GET /roles?q=roleId==/roleName==
  (no /roles/{id} endpoint exists); --privileges adds expand=privileges
- Role.Privileges is now []RolePrivilege (API returns objects)
- role get: interactive role picker when --id/--name omitted, optional
  "Display role privileges? [y/Q]" prompt in table output, privileges
  sorted by service and name, status color-coded, CSV output support
- role create: --name/--description/--privilege (names or IDs resolved
  to IDs) and --from-file using the API request shape
- replace role update (non-existent endpoint) with add-privileges and
  remove-privileges (PUT /roles/{id|name/<name>}/add|removePrivileges)
- role delete: support --name
- docs, README, completions; bug record in docs/issues/pending
- role edit: TUI to add/remove privileges, grouped by service, then by
  object with one column per action (view/create/update/delete/execute/
  changeperm); non-matching names listed under Other; review step with
  add-before-remove apply and a guard against removing all privileges
- role add-privileges / remove-privileges open the editor in add-only /
  remove-only mode when --privilege is omitted on a terminal
- role create: interactive wizard (name, description, optional clone
  source, editor) and non-interactive --from-role <name|id>
- role picker is now a filterable huh select
- client: GroupPrivileges, DiffPrivileges, FindRole with tests;
  internal/tui/privmatrix Bubble Tea model with tests
- deps: charmbracelet/huh, bubbletea, bubbles
- docs: role.md editor/edit/--from-role, README, docs/CLAUDE.md deps,
  completions; CR-0040 moved to pending
- internal/tui/prompt.go: Prompter with Text, Secret, Select, MultiSelect,
  Confirm, Timezone and generic PickOne; huh forms on a terminal
  (arrows, / filter, checkboxes with defaults pre-checked), line-based
  fallback with the historical input format when stdin/stderr is not a
  terminal; one shared buffered reader so piped answers are not lost
  between prompts; IICS_ACCESSIBLE=1 enables huh accessible mode
- cmd/user_prompt.go: promptText/Password/Select/MultiSelect/YesNo and
  promptTimezone delegate to the Prompter (signatures unchanged);
  promptUserSearch uses the shared helpers
- cmd/role_prompt.go: pickRole uses tui.PickOne
- tests for the line-based path, including sequential piped prompts
- docs: interactive.md (keys, accessible mode, piped format), links from
  user/group/environment/agent/role docs, IICS_ACCESSIBLE in README;
  CR-0041 updated for the line-based fallback decision
- internal/tui/userwizard.go: huh form with Identity, Single sign-on
  (SSO only), Details and Membership pages; user name suggestion,
  required-field and email validation, filterable group and role
  checklists pre-checked with current membership, time zone select on
  update; review step (create summary / update diff) with apply, back
  to editing, or cancel; create requires at least one group or role
- update shows user name, authentication and state read-only instead of
  prompting for values the update API ignores
- client: aliasName on create (documented as required for SSO)
- cmd/user.go: runUserWizard delegates to tui.RunUserWizard; cancel
  prints "Canceled." instead of failing
- tests for change/summary builders, user name suggestion, email check
- docs: user.md wizard section; CR-0041 progress; new bug record for the
  existing V2 user update failure (403 REPO_10704)
- internal/tui/review.go: shared confirmReview (apply / back / cancel,
  apply hidden when nothing to apply), SetChanges (+/- lines),
  requiredUnique and atLeastOne validators; user wizard reuses them
- internal/tui/groupwizard.go: create asks name (duplicates rejected),
  description and roles (filterable checklist, at least one); update
  shows name/description read-only, roles pre-checked, review of +/-
  role changes, no-change review offers only back/cancel
- internal/tui/runtimewizard.go: name (duplicates rejected), description,
  shared flag, filterable checklist of unassigned agents (file-seeded
  agents pre-checked), review; replaces the add/remove/done menu loop
- cmd: group and environment wizards delegate to internal/tui; cancel
  prints "Canceled." instead of failing; remove unused promptMultiSelect
  wrapper and truncate helper
- tests for review helpers and agent list building
- docs: group.md and environment.md wizard descriptions; CR-0041 progress
- pickUserGroup, pickAgent, pickAgentService use tui.PickOne
- confirmAction replaces 12 duplicated [y/N] confirmation blocks with
  identical prompt text and behavior (plain line input kept for scripts)
- docs: interactive.md confirmations section
- CR-0041 acceptance criteria complete; moved to pending
- user update-roles / update-groups: --id|--username (aliases --uid,
  --uname), --add and --remove (combinable) or --replace (exclusive, empty
  removes all); de-duplicated, case-insensitive names validated against the
  org before any change; no-ops reported and skipped; additions before
  removals; resulting user printed in the --output format
- role assignment endpoints match the role display name (verified on dev);
  commands send the display name and accept role name or display name
- user update --interactive edits only group and role assignments and
  applies them through the V3 assignment endpoints
- client: Add/RemoveUserRoles, Add/RemoveUserGroups, PlanMembership with tests
- shared printUser used by user get and the new commands
- docs: user.md, README, completions; bug record updated with mitigation
- user edit: terminal-only form for user group and role assignments
  (no --interactive switch needed); applies changes via the V3
  add/remove assignment endpoints and prints the resulting user
- user update kept as a hidden, deprecated alias of user edit;
  --interactive accepted and ignored
- remove user update --from-file and the V2 scalar update
  (Client.UpdateUser, updateUserV2Request, doXML, TestUpdateUser): it
  never worked against the API (HTTP 405 on V3, 400/403 on V2)
- docs: user.md "user edit" section, README, interactive.md, completions;
  CR-0043 updated; user update bug moved to pending
…s API

- client: ObjectACL model (principal {type, name}, permissions {read,
  update, delete, execute, changePermission}); list, get, create (POST per
  principal), update (PUT per ACL ID), delete one / all, checkAccess;
  DiffACLs and ParseACLPermissions with tests. Removes the previous
  guessed structs and the non-existent PUT /objects/<id>/permissions
- commands: get, add, update, delete (--acl-id | --user | --group | --all),
  set (--from-file, --prune, --dry-run), check (--asset-type); objects by
  --object-id or --path/--type (lookup); changes print the resulting ACLs
- verified against dev on a throwaway project
- docs: permission.md rewritten, README, completions; bug moved to pending
- internal/tui/grid: generic grid core extracted from privmatrix (cells,
  pending-change marks, cursor, row/column toggles, filter with section
  headers, scrolling, detail footer, clear-row key, action keys, empty text)
- privmatrix is now a thin adapter over the grid; role edit unchanged
- internal/tui/acleditor.go: EditACLs grid of principals x read/update/
  delete/execute/changePermission; n adds a user group or user, d clears a
  row (ACL deleted); review with +/~/- lines and a warning when your own
  change permission is removed; returns a DiffACLs plan
- permission edit: --object-id, --path/--type, or a project -> folder ->
  asset picker; checkAccess guard; applies via applyACLPlan (shared with
  permission set) and prints the resulting ACLs
- fix huh cancel hints: Ctrl+C cancels lists (Esc clears the filter)
- docs: permission.md edit section, interactive.md, agent.md, README,
  comparison, completions; CR-0042 moved to pending
- bare "iics" opens a main menu when stdin and stdout are terminals;
  otherwise prints help as before; opt out with IICS_NO_MENU=1, config
  ui.menu: false, or CI; "iics menu" (alias tui) opens it explicitly
- entries run the real command as a subprocess (terminal passed through,
  --profile and explicitly set global flags appended), print the command
  line, show a done/failed status, pause, and return to the last entry;
  Ctrl+C cancels only the running command
- header with profile, org, user and session time from the session cache;
  session-only profile switch (p) and "Set as default profile"
- production profiles (config production: true, or prd/prod name hint) get a
  red marker and a confirmation before entries that change data;
  profile add/edit ask for the production flag
- first run without profiles starts profile add; accessible mode and small
  terminals use a numbered line menu
- internal/menu with tests (open decision, entries, model, loop with fake
  runner); config production/UI settings with tests
- docs: menu.md, README, interactive.md, profile.md, completions
…ntry

- agent installer-download --interactive: OS picker, "Download to" prompt
  pre-filled with the default temp path (directories and ~/ supported),
  and an existing-file prompt
- existing destination file: SHA-256 compared with the installer checksum
  and reported; scripts skip a matching file (download otherwise),
  interactive mode asks (default No when it matches, Yes otherwise),
  --force always downloads; fetched checksum is reused for --verify
- client: SHA256File, CompareChecksum, DownloadOverExisting with tests
- menu: "Show agent installer info" entry; download entry runs
  installer-download --interactive --progress
- docs: agent.md, menu.md, CR-0044 follow-up; completions
…CR-0045)

- profile config newUser: domain (default: domain of the profile username),
  userNamePattern (default {firstName}.{lastName}.{profileName}@{domain}),
  emailPattern (default {firstName}.{lastName}@{domain}); placeholders
  firstName, lastName, firstInitial, lastInitial, profileName, domain
- config.ExpandUserPattern validates placeholders and missing values
- user create --interactive: user name and email show the generated value
  in gray; right arrow or ctrl+e fills it in for editing, empty uses it;
  notes under the field explain the pattern or why there is no suggestion
- profile show lists Production and the effective new-user settings
- tests for pattern defaults/expansion and wizard suggestions
- docs: user.md, profile.md, README; CR-0045 in pending
- menu: "Users > Show user" runs user get
- user get without --id/--username on a terminal asks for a user name, ID,
  or part of a name/email; same prompt replaces the two-step search menu
  in user edit / user delete
- GetUser / GetUserByName use the q=userId== / q=userName== filters
  instead of listing every user (the API supports exact matches only)
- SearchUsers also matches first, last and full name and email; several
  matches open a filterable picker (user name, name, email, state)
- tests updated; docs: user.md (finding a user), menu.md, CR-0044 follow-up
- user create --interactive: leaving the User name field looks up the
  effective name (typed or suggested) server-side and shows
  'user "<name>" already exists (ID <id>)'; cached per name, lookup errors
  do not block
- client: FindUserByName (nil when not found); GetUserByName uses it
- tests; docs: user.md, CR-0045 follow-up
IICS rejects removing a user's last directly assigned role with
V3API_IDSError_044 ("The group must have at least one role"), even when
user groups grant other roles.

- user update-roles and user edit reject such a change before any API
  call; the edit wizard review cannot be applied in that case
- user update-roles skips additions of roles granted by the user's
  groups and reports them on stderr
- the user wizard hides roles granted by the selected groups (except
  current direct roles) and lists them in the field description
- document both rules in docs/documentation/user.md
The menu runs in the alternate screen while commands run on the normal
screen, which was only cleared after the "Press Enter" pause. The first
command showed the shell output from before iics started, and entries
that returned to the menu without a pause (profile switch, declined
production confirmation, empty prompt) left their prompts above the
next command. Clear the screen as soon as an entry is chosen.
- profile add, profile edit, login (missing profile) and first-run setup
  share one paged form: connection (region list or custom login URL),
  options, keychain, per-profile new user overrides, review
- global newUser defaults with per-field profile overrides; profile show
  lists effective values and their source
- new "iics config edit" for global settings: new user defaults, table
  theme with preview, header color, colors, responsive tables, HTTP
  timeout, main menu; menu entry under Session
- Config.Save now writes httpTimeout, ui and newUser (profile saves used
  to drop httpTimeout and ui.menu)
- remove the line-based profile prompts and the theme prompt from the
  profile commands
go install names the binary after the main package directory, so
installing from the module root produced iics-cli while release
archives, make build and all documentation use iics.

- move main.go to cmd/iics/main.go
- point Makefile build, install and completions targets at ./cmd/iics
- point goreleaser and the CI build job at ./cmd/iics
- update the README install command and the directory layout docs
- go mod tidy: mark github.com/spf13/pflag as a direct dependency

The install command is now:
go install github.com/jbrazda/iics-cli/cmd/iics@latest
Add a Session entry that lists the configured profiles and runs
'profile delete <name>' for the picked one. When the active profile is
deleted, the menu continues on the default profile, or on the first
remaining profile when there is no default.
globalFlagArgs used PersistentFlags().Visit on the root command, but
cobra parses on the invoked command's own flag set, so the root set
never recorded any flag as set and nothing was passed through. A menu
started with --config listed profiles from that file while the commands
it ran read ~/.iics/config.yaml. Check Flag.Changed with VisitAll
instead.
Add a project markdownlint-cli2 config (no line length limit, repeated
headings allowed under different parents, H1 allowed next to a front
matter title) and one for .github templates, then fix what is left:
table alignment and escaped pipes, code fence languages, hard tabs and
blank lines.

Also repair two damaged pages: a stray example in activitylog.md that
sat outside its code blocks and turned the rest of the page into code,
and a leftover fragment of an old user get section in user.md.

Test fixtures under testdata/ are not touched.
The hard-coded path only exists on the MacPorts machine. Completed change
requests and bug reports keep the old path as historical records.
… (CR-0047)

Connections (V2, JSON):
- update uses POST /connection/<id>; --partial sends Update-Mode: PARTIAL
- create/update send the file as-is and add "@type":"connection"
- get --name; new test, search, objects and metadata subcommands
- list --type/--name filter client-side (the API ignores them)
- Connection struct extended with verified fields

Connectors (new): connector list and connector metadata, including
attributes parsed from the CCI definition (cciMeta).

Projects and folders:
- project update uses PATCH by --id or --project-name
- folder update percent-encodes names, validates flags and updates by ID
  via /folders/<id>; --project-id is deprecated (documented
  /projects/<id>/folders/<id> returns 404)
- --interactive pickers driven by the objects API with name filter,
  plus "Projects and folders" menu entries

Response shapes verified against a DEV org; CR moved to pending.
…047)

- project list [--name REGEX] [-i]
- folder list [--name REGEX] [--project-name | --project-id | --pick-project] [-i]
- regex matches the full project/folder path, case-insensitive
- created time and created by come from the internal FRS API
  (/frs/api/v1, IDS-SESSION-ID), user IDs resolved via the users API;
  falls back to the objects API without the created columns when FRS fails
- menu: List projects, List folders, List folders in a project
- huh pickers, text and yes/no prompts: Esc cancels (closes/clears an
  open filter first), q cancels lists and yes/no prompts but is typed in
  text inputs and filters; multi-page wizards keep ctrl+c only
- [y/N] confirmations, login profile creation, role privilege prompt and
  the menu pause read single keys in raw mode on a terminal, so arrow
  keys are ignored instead of echoed as ^[[A; piped answers still work
- menu pause: Enter/Esc return to the menu, q/ctrl+c quit
- wizards (user, profile, group, environment, config) and role create
  cancel with Esc or ctrl+c; q is always typed since they have text inputs
- forms run inside a small Bubble Tea model that applies the cancel keys
  and renders a hint line: "esc, q (in lists) or ctrl+c to cancel" for
  pickers and questions, "esc or ctrl+c to cancel" for wizards
Read and change Secure Agent service properties of a single agent, such as
the Process Server cluster and database settings. There is no REST API for
this; the commands use the Administrator form /runtime/app/agent.do with the
REST session as USER_SESSION cookie and a double-submit CSRF token, submit
the whole form as the browser does, and verify the change by reading back.

- agent configs get: filter by service, type, name regex, overridden
- agent configs set: --set (value @file), --reset, --from-file, --dry-run,
  confirmation, refuses agents whose group has group-level properties
  unless --force, refuses agent system properties (server ignores them)
- --debug masks Cookie and Set-Cookie headers
…0049)

- agent configs set --from-file reads JSON or YAML: a nested
  service/type/name map (null resets) or a list of {property, value, reset};
  only the listed properties change
- agent configs get --export writes the filtered properties in that format
  (YAML, or JSON with -o json), so overrides can be copied between agents
- set lists the changed services with 'iics agent restart' commands, since
  Process Server keeps the old values until restarted manually
- docs: works for any agent service mix; corrected Process Server restart
  behavior
- iics agent rename --id|--fid|--name|--hostname --new-name renames an agent
  through the agent form (installer registers the host name; standard names
  are logical, e.g. CAI-A03). Trimmed, max 100 chars, unique in the org,
  verified with the agent API.
- agent configs get hides the agent's own Agent Core / Agent Manager / Tomcat
  rows (a hidden legacy form section the UI never shows and the server
  ignores) unless --include-hidden or --service agent is given.
- iics agent configs edit: services -> properties -> property editor ->
  review and apply, in the style of role edit; agent picker without flags
- one-line values in an input; YAML single quotes added back automatically;
  sensitive values masked
- multi-value properties (LDAP, DB connection properties, logging) in an
  entry editor: edit/add/remove entries, edit as text or in $EDITOR, reset,
  undo; unchanged entries keep their exact text
- review shows entry-level changes for list properties
- menu: Environments and agents > Edit agent properties
- NAME/PROPERTY columns no longer wrap (renderer moved them last)
- parse custom property rows and the custom types each service offers
- agent configs get lists custom properties (OVERRIDDEN shows 'custom')
- agent configs set --add / --remove; --set changes a custom value;
  --reset removes a custom property; --add-missing adds properties from
  --set/--from-file that do not exist (copying settings between agents)
- change files: list items take add/remove/sensitive; null removes customs
- type labels from the UI (Tomcat, DTM) are accepted in property names
- agent configs edit: + Add custom property, edit value, remove/keep
- rows are added after the last custom row with a millisecond ID; the
  empty template row is replaced or restored like the Administrator UI
…CR-0049)

- agent configs set --reset-all [--service]: reset every overridden
  standard property like the UI's Reset All (custom kept, sensitive skipped)
- editor: Reset all to defaults (all services) and per service, with a
  confirmation listing the properties
- agent details -i (or no agent flag in a terminal): pick the agent, then
  services summary, details, full details or service properties
- menu: Environments and agents > Show agent details
- agent configs get wraps long property names in the cell instead of
  falling back to the vertical layout
Recorded against a test org; host names, user names, the organization
name and the org ID are masked.
scripts/demo/record.py records docs/demo/iics-demo.cast from
scenes.json and masks sensitive output with same-length replacements.
The rules live in scripts/demo/masks.local.json, which is ignored by
git; masks.example.json documents the format. make demo builds iics,
records the cast and renders the GIF with agg.
…errides

The Administrator UI now bundles the agent form's property rows into the
configFormJson field (POP-88806); posting them as flat parameters exceeds
Tomcat's maxParameterCount and the server answers HTTP 500 CMN_001. Pack
the rows the same way when the form has that field.

Values that differ from the default only in line endings, trailing
whitespace or surrounding blank lines are no longer reported as overridden,
and whitespace-only sets, sets to the default and resets of non-overridden
properties are no longer shown as changes.
Process Server can take well over five minutes to become operational after
a start, passing through RUNNING subState -1 and 2 before 0, so restart
--blocking timed out with the old 300 second default. start and restart
now default --max-wait-time to 1200 seconds (stop keeps 300), poll lines
label subStates (-1 Initializing, 2 Starting, 0 Operational), and a
timeout reports the last state seen.
The API's customized flag only marks custom properties (Custom
Configuration Details); overridden standard properties always come back
with customized false. Compute an overridden field from value and default
with SameValue, and replace the CUSTOMIZED column with OVERRIDDEN
(custom, yes or empty), matching agent configs get.
The skills lived only under the gitignored .claude/ and were copied between
machines by hand. Track .claude/skills/ (settings.local.json stays ignored).

commit: dev-only branch guard, the full CLAUDE.md check list (gofmt, vet,
golangci-lint, tests), docs/completions/CHANGELOG and CR/bug move checks,
staging by path instead of git add -A, no Co-Authored-By trailer.

release: plain go instead of the MacPorts path, asks before moving pending
CRs and bugs, and lands dev on main through a release PR - fast-forward by
default (keeps every commit, no back-merge), squash on request - instead of
an ff push that only worked through the ruleset bypass.
@jbrazda
jbrazda merged commit 47a1fdf into main Oct 24, 2026
16 checks passed
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.

1 participant