- name
- subaccount-roles-import
- description
- Assign Neo application roles and group memberships into a CF subaccount after apps are deployed. Reads ~/.neo-migration/$SUBACCOUNT/$CF_SUBACCOUNT_GUID/neo-roles.json (produced by subaccount-roles-export), resolves live XSUAA appIds from deployed CF apps, adds role-templates from those apps to the role collections created by authentication-xsuaa, and assigns users via BTP CLI. Consent files live under ~/.neo-migration-consents/$SUBACCOUNT/. Generates a manual checklist for unresolved apps, group role links, and the Everyone role. MUST run after all applications are deployed to CF.
- disable-model-invocation
- false
- allowed-tools
- Read, Write, Glob, Bash(curl *), Bash(python3 *), Bash(btp *), Bash(cf *), Bash(echo *), Bash(cat *), Bash(ls *), Bash(mkdir *)
# Subaccount Roles Import
Assign Neo application roles and group memberships into CF role collections after app deployment.
## Purpose
This skill reads the structured roles export produced by `subaccount-roles-export` and completes the authorization setup in CF by:
- Resolving the live XSUAA `appId` for each deployed application (e.g. `myapp!t1234`)
- Adding the corresponding role-templates from each deployed XSUAA app to its role collections
- Assigning users to role collections via the BTP CLI
- Assigning group members to group role collections
- Generating a manual checklist for unresolvable apps, group→role links, and the Everyone role
> **Must run after all applications are deployed.** This skill requires live XSUAA apps to exist in CF — the `appId` (e.g. `myapp!t1234`) is only available after the first `cf deploy`. Role collections are created by `authentication-xsuaa` via `xs-security.json` + deployment; this skill does NOT create role collections.
> **Role collections are owned by `authentication-xsuaa`.** The `xs-security.json` generated by that skill defines the role collection names and role-template references. This skill only links the deployed role-templates into those collections and assigns users.
> **The "Everyone" role cannot be directly migrated.** In Neo, the Everyone role grants access to all authenticated users implicitly. In CF, you must explicitly assign role collections to all users. This skill flags this as a manual step.
## Prerequisites
1. **`subaccount-roles-export` must have run** — `~/.neo-migration/$SUBACCOUNT/$CF_SUBACCOUNT_GUID/neo-roles.json` must exist
2. **All applications must be deployed to CF** — each app's `authentication-xsuaa` skill must have run, `xs-security.json` must be deployed, and `cf deploy . -f` must have completed successfully for every app
3. **BTP CLI installed and logged in:**
```bash
btp target
```
If not logged in, instruct the user to run:
```bash
btp login --sso
```
4. **Target CF subaccount ID** — the GUID of the CF subaccount
## Input Resolution
### Step 0: Resolve Required Parameters
**0a. Resolve subaccount directory:**
```bash
_NEO_MIGRATION_HOME="${XDG_DATA_HOME:-${APPDATA:-$HOME}}/.neo-migration"
_NEO_CONSENTS_HOME="${XDG_DATA_HOME:-${APPDATA:-$HOME}}/.neo-migration-consents"
export SUBACCOUNT="<Neo subaccount technical name>"
_CF_ORG=$(cf target 2>/dev/null | awk '/^org:/{print $2}')
CF_SUBACCOUNT_GUID=$(btp list accounts/subaccount 2>/dev/null | awk -v org="${_CF_ORG}" '
NR > 2 { guid=$1; subdomain=$3; if (index(org, subdomain) > 0) { print guid; exit } }
')
[ -n "${CF_SUBACCOUNT_GUID}" ] || { echo "ERROR: Could not resolve CF_SUBACCOUNT_GUID — check btp login and cf target." >&2; exit 1; }
_SUBACCOUNT_DIR="${_NEO_MIGRATION_HOME}/${SUBACCOUNT}/${CF_SUBACCOUNT_GUID}"
```
> When invoked by `subaccount-migration-orchestrator`, `SUBACCOUNT` and `CF_SUBACCOUNT_GUID` are already known. When invoked standalone, `SUBACCOUNT` must be provided and `CF_SUBACCOUNT_GUID` is resolved automatically.
**0b. Read the export file:**
```bash
cat "${_SUBACCOUNT_DIR}/neo-roles.json"
```
If the file does not exist, stop and instruct the user to run `subaccount-roles-export` first.
**0c. Check for existing CF config:**
```bash
if [ -f .migration/cf-migration-config.json ]; then
cat .migration/cf-migration-config.json
fi
```
Read `cfSubaccountId` if present and assign it to the shell variable:
```bash
CF_SUBACCOUNT_ID=$(python3 -c "
import json, os
path = '.migration/cf-migration-config.json'
if os.path.exists(path):
with open(path) as f:
print(json.load(f).get('cfSubaccountId', ''))
" 2>/dev/null || echo "")
```
**0d. Read the trust import report to determine the IdP origin key:**
```bash
if [ -f "${_SUBACCOUNT_DIR}/neo-trust-import-report.json" ]; then
cat "${_SUBACCOUNT_DIR}/neo-trust-import-report.json"
fi
```
Extract the `originKey` from the first successfully imported IdP:
```bash
IDP_ORIGIN=$(python3 -c "
import json, sys, os
path = os.path.expanduser('~') + '/.neo-migration/${SUBACCOUNT}/${CF_SUBACCOUNT_GUID}/neo-trust-import-report.json'
try:
with open(path) as f:
report = json.load(f)
imported = report.get('imported', [])
already = report.get('alreadyConfigured', [])
all_idps = imported + already
print(all_idps[0]['originKey'] if all_idps else 'sap.default')
except Exception:
print('sap.default')
" 2>/dev/null || echo "sap.default")
```
If the file does not exist or contains no imported IdPs, fall back to `sap.default` and note it in the report:
> "No trust migration report found — using `sap.default` as the IdP origin for user assignments. If users authenticate via a custom IdP, re-run this skill after completing `subaccount-trust-migrator`."
**0e. Ask the user** for any values still missing:
1. "What is the GUID of the target CF subaccount?"
**0f. Save CF config** if not already present:
Write `{ "cfSubaccountId": "<guid>" }` to `.migration/cf-migration-config.json` if it doesn't exist.
## Step 1: Validate Session and Input
**1a. Verify BTP CLI session:**
```bash
btp target
```
If this fails, stop and tell the user:
> "No active BTP CLI session found. Please run `btp login --sso` in your terminal, then re-invoke this skill."
**1b. Check for data to process:**
If both `applications` and `groups` arrays are empty in the export, inform the user:
> "The Neo subaccount has no application roles or groups configured. Nothing to import."
Then stop — this is a successful no-op.
## Step 2: Resolve Deployed XSUAA Apps
Fetch the list of deployed XSUAA applications from the CF subaccount:
```bash
XSUAA_APPS=$(btp --format json list security/app --subaccount "${CF_SUBACCOUNT_ID}")
```
Build a map of `appName → appId` using jq:
```bash
# For each app name from neo-roles.json, find its deployed appId
# XSUAA appIds have the format: appname!tNNNNN
# Match by the prefix before the '!' separator
# NOTE: BTP CLI returns .appid (lowercase) and .xsappname — not .name or .appId
echo "$XSUAA_APPS" | jq -r '.[] | "\(.xsappname) \(.appid)"'
```
For each application in `neo-roles.json`:
```bash
APP_NAME="<appName from neo-roles.json>"
APP_ID=$(echo "$XSUAA_APPS" | jq -r --arg name "$APP_NAME" \
'.[] | select(.xsappname == $name or (.appid | startswith($name + "!"))) | .appid' | head -1)
```
**Classification:**
| Condition | Action |
|-----------|--------|
| `APP_ID` found | Proceed to Steps 3 and 4 for this app |
| `APP_ID` not found | Add to manual checklist: "App `{appName}` not found in CF — ensure it has been deployed and `authentication-xsuaa` has been run for it. Re-run this skill after deployment." Skip role-template assignment for this app; still attempt user assignments if role collections exist. |
## Step 3: Add Role-Templates to Role Collections
For each application with a resolved `APP_ID`, for each role in `application.roles[]`:
**3a. Determine the role collection name:**
First, try to read `xs-security.json` from the application directory to find the exact collection name defined there:
```bash
# If app directories are known (e.g. from cf-migration-config.json or user input):
APP_DIR="<path to app source directory>"
if [ -f "${APP_DIR}/xs-security.json" ]; then
# Find role-collection that references this role-template
COLLECTION_NAME=$(jq -r --arg role "${ROLE_NAME}" \
'.["role-collections"][] | select(.["role-template-references"][] | contains($role)) | .name' \
"${APP_DIR}/xs-security.json" | head -1)
fi
```
If `xs-security.json` is not found or the role is not listed there, fall back to the naming convention:
```bash
COLLECTION_NAME="${APP_NAME}-${ROLE_NAME}"
```
**3b. Add the role-template to the collection:**
```bash
btp add security/role "${ROLE_NAME}" \
--to-role-collection "${COLLECTION_NAME}" \
--of-app "${APP_ID}" \
--of-role-template "${ROLE_NAME}" \
--subaccount "${CF_SUBACCOUNT_ID}"
```
**Handle responses:**
| Outcome | Action |
|---------|--------|
| Success (exit 0) | Mark as `role_assigned` |
| "already exists" / conflict | Mark as `already_assigned` — treat as success |
| "read-only RoleCollection" | Mark as `already_assigned` — role-template is already bound by `authentication-xsuaa` during deploy; no action needed |
| Role collection not found | Add to manual checklist: "Role collection `{collectionName}` not found — ensure `authentication-xsuaa` was run for `{appName}` and the app is deployed. Create the collection manually or re-run `authentication-xsuaa`." |
| Any other error | Mark as `failed`, capture error, continue |
## Step 4: Assign Users to Role Collections
**4a. Assign users from application role assignments:**
For each application, for each role, for each user in `role.userAssignments[]`:
```bash
btp assign security/role-collection "${COLLECTION_NAME}" \
--to-user "${USER_ID}" \
--of-idp "${IDP_ORIGIN}" \
--subaccount "${CF_SUBACCOUNT_ID}"
```
**Handle responses:**
| Outcome | Action |
|---------|--------|
| Success (exit 0) | Record as `assigned` |
| "user not found" error | Add to manual steps: "User `{userId}` not found in CF — the user must log in at least once to be created. Assign manually in BTP Cockpit > Security > Users." |
| Any other error | Record as `failed`, capture error, continue |
**4b. Create and populate group role collections:**
For each group in `groups[]`:
The group role collection may already exist if `subaccount-trust-migrator` created it for assertion-based group rules. Check first:
```bash
EXISTING=$(btp --format json list security/role-collection --subaccount "${CF_SUBACCOUNT_ID}" | \
jq -r --arg name "${GROUP_NAME}-Group" '.[] | select(.name == $name) | .name')
```
If it does not exist, create it:
```bash
btp create security/role-collection "${GROUP_NAME}-Group" \
--description "Migrated from Neo group: ${GROUP_NAME}" \
--subaccount "${CF_SUBACCOUNT_ID}" 2>/dev/null || true
```
Assign users from `group.userAssignments[]`:
```bash
btp assign security/role-collection "${GROUP_NAME}-Group" \
--to-user "${USER_ID}" \
--of-idp "${IDP_ORIGIN}" \
--subaccount "${CF_SUBACCOUNT_ID}"
```
**4c. Document group→role links in the manual checklist:**
For each entry in `group.roleAssignments[]`, CF role collections cannot contain other role collections. Each group→role link must be handled by adding the role-template from the referenced app to the group's collection:
```bash
btp add security/role "${ROLE_NAME}" \
--to-role-collection "${GROUP_NAME}-Group" \
--of-app "${APP_ID}" \
--of-role-template "${ROLE_NAME}" \
--subaccount "${CF_SUBACCOUNT_ID}"
```
If the referenced app is not deployed yet, add to manual checklist:
> "**{groupName}-Group**: In Neo this group had role **{applicationName}/{roleName}**. Add the role-template from `{applicationName}` (appId: `{appId}`) to this role collection after the app is deployed."
## Step 5: Build Manual Checklist
Collect all items that could not be automated:
| Condition | Manual Step |
|-----------|-------------|
| Always | "The implicit 'Everyone' role in Neo has no CF equivalent. Explicitly assign the appropriate role collection(s) to all users who should have basic authenticated access, or configure a default role collection in the trust configuration." |
| Any app not found in CF | "Deploy `{appName}` to CF (`cf deploy . -f` from the app directory), then re-run `subaccount-roles-import` to complete role-template and user assignments for this app." |
| Any role collection not found | "Role collection `{collectionName}` not found — ensure `authentication-xsuaa` was run and the app is deployed. Create manually in BTP Cockpit > Security > Role Collections, then add role-template `{roleName}` from app `{appId}`." |
| Any user assignment failure | "User `{userId}` not found — ensure they have logged in at least once. Assign `{collectionName}` manually in BTP Cockpit > Security > Users." |
Ver no GitHub