Package: cortexapps-cli
Installationpypi.orghomebrewUsageConfig fileEnvironment VariablesCommandsExamplesExport from one tenant; import into anotherIterate over all domainsIterate over all teamsIterate over all servicesGet git details for a serviceAdd a suffix to all x-cortex-tag values for servicesAdd a group to all domainsRemove a group from domainsAdd a domain parent to a single serviceAdd a github group as an owner to a serviceModify all github basepath values for domain entitities, changing ‘-’ to ‘_’Modify deploys based on selection criteriaCreate a backup of all scorecardsCreate a copy of all scorecards in draft modeReplace scorecards with draft versions and delete the draft versionsGet draft scorecards, change draft to false and save on diskDelete all draft scorecardsCompare scorecard scores and levels for two scorecardsDelete all Workday teamsInstallationpypi.orgpipinstallcortexapps-cliUsing a python virtual environment:VENV_DIR=~/.venv/cortexpython3-mvenv$VENV_DIRsource$VENV_DIR/bin/activatepipinstallcortexapps-clihomebrewbrewtapcortexapps/tapbrewinstallcortexapps-cliUsageConfig fileThe CLI requires an API key for all operations.  This key is stored in a config file whose default location is~/.cortex/config.
This path can be overridden with the-cflag.Minimal contents of the file:[default]
api_key = REPLACE_WITH_YOUR_CORTEX_API_KEYIf you have multiple Cortex instances, you can create a section for each, for example:[default]
api_key = REPLACE_WITH_YOUR_CORTEX_API_KEY

[my-test]
api_key = REPLACE_WITH_YOUR_CORTEX_API_KEY
base_url = https://app.cortex.mycompany.comNOTE:if not supplied, base_url defaults tohttps://app.getcortexapp.com.The CLI will retrieve configuration data from the[default]section unless you pass the-t/--tenantflag.For example, to list all entities in themy-testtenant, run the following command:cortex-tmy-testcataloglistIf the config file does not exist, the CLI will prompt you to create it.Environment VariablesThe CLI supports the following environment variables.  If provided, the Cortex config file will not be read.CORTEX_API_KEYCORTEX_BASE_URL - this is optional if using Cortex cloud; defaults tohttps://app.getcortexapp.comExample:export CORTEX_API_KEY=<YOUR_API_KEY>CommandsRuncortex -hto see a list of all commands:Runcortex <subcommand> -hto see a list of all commands for each subcommand.For example:cortexaudit-logs-husage: cortex CLI audit-logs [-h] {get} ...

positional arguments:
  {get}       audit logs help
    get       retrieve audit logs

options:
  -h, --help  show this help message and exitExamplesAlmost all CLI responses return JSON or YAML.  Tools likejqandyqwill be helpful to extract content from these responses.Export from one tenant; import into anotherThis example shows how to export from a tenant namedmyTenant-devand import those contents into a tenant
namedmyTenant.Your cortex config file will require api keys for both tenants.  It would look like this:[myTenant]
api_key = <your API Key for myTenant>

[myTenant-dev]
api_key = <your API Key for myTenant-dev>Exportcortex-tmyTenant-devbackupexportGetting resource definitions
 -->  my-resource-1
 Getting catalog entities
 -->  my-domain-1
 -->  my-service-1
 -->  my-service-2
 Getting IP Allowlist definitions
 Getting scorecards
 -->  my-scorecard-1
 Getting teams
 -->  my-team-1
 -->  my-team-2

 Export complete!
 Contents available in /Users/myUser/.cortex/export/2023-11-19-14-58-14Importcortex-tmyTenantbackupimport-d<directorycreatedbyexport>NOTE:some content will not be exported, including integration configurations and resources that
are automatically imported by Cortex.  Cortex does not have access to any keys, so it cannot export any
integration configurations.Iterate over all domainsfordomainin`cortexcataloglist-tdomain|jq-r".entities[].tag"|sort`;doecho"domain =$domain";doneIterate over all teamsforteamin`cortexcataloglist-tteam|jq-r".entities[].tag"|sort`;doecho"team =$team";doneIterate over all servicesforservicein`cortexcataloglist-tservice|jq-r".entities[].tag"|sort`;doecho"service =$service";doneGet git details for a servicecortexcatalogdetails-tmy-service-1|jq".git"{
  "repository": "my-org/my-service-1",
  "alias": null,
  "basepath": null,
  "provider": "github"
}Add a suffix to all x-cortex-tag values for servicesforservicein`cortexcataloglist-tservice|jq-r".entities[].tag"|sort`;docortexcatalogdescriptor-y-t${service}|yq'.info.x-cortex-tag |= . + "-suffix"'|cortexcatalogcreate-f-doneThis example combines several CLI commands:the for loop iterates over all servicesthe descriptor for each service is retrieved in YAML formatthe YAML descriptor is piped to yq where the value ofx-cortex-tagis retrieved and modified to add “-suffix” to the endthe modified YAML is then piped to the cortex catalog command to update the entity in cortexNOTE:Any cortex commands that accept a file as input can also receive input from stdin by specifying a “-” after the -f
parameter.Add a group to all domainsfordomainin`cortexcataloglist-tdomain|jq-r".entities[].tag"|sort`;docortexcatalogdescriptor-y-t${domain}|yq-e'.info.x-cortex-groups += [ "my-new-group" ]'|cortexcatalogcreate-f-doneRemove a group from domainsfordomainin`cortexcataloglist-tdomain-gmy-old-group|jq-r".entities[].tag"|sort`;docortexcatalogdescriptor-y-t${domain}|yq-e'.info.x-cortex-groups -= [ "my-old-group" ]'|cortexcatalogcreate-f-doneAdd a domain parent to a single servicecortexcatalogdescriptor-y-tmy-service|yq-e'.info.x-cortex-domain-parents += { "tag": "my-new-domain" }'|cortexcatalogcreate-f-Add a github group as an owner to a servicecortexcatalogdescriptor-y-tmy-service|yq-e'.info.x-cortex-owners += { "name": "my-org/my-team", "type": "GROUP", "provider": "GITHUB" }'|cortexcatalogcreate-f-Modify all github basepath values for domain entitities, changing ‘-’ to ‘_’fordomainin`cortexcataloglist-tdomain|jq-r".entities[].tag"`;docortexcatalogdescriptor-y-t${domain}|yq".info.x-cortex-git.github.basepath |= sub(\"-\", \"_\")"|cortexcatalogcreate-f-doneModify deploys based on selection criteriaThis example fixes a typo in the deployment environment field, changing PYPI.org to PyPI.org.It loops over each selected array element based on the search criteria, removes the uuid attribute (because that is not included in the payload),
assigns the environment attribute to the correct value and invokes the CLI with that input.cortexdeployslist-tcli>/tmp/deploys.jsonforuuidin`cat/tmp/deploys.json|jq-r'.deployments[] | select(.environment=="PYPI.org") | .uuid'`docat/tmp/deploys.json|jq".deployments[] | select (.uuid==\"${uuid}\") | del(.uuid) | .environment = \"PyPI.org\""|cortexdeploysupdate-by-uuid-tcli-u${uuid}-f-doneCreate a backup of all scorecardsfortagin`cortexscorecardslist|jq-r".scorecards[].tag"`doecho"backing up:${tag}"cortexscorecardsdescriptor-t${tag}>${tag}.yamldoneCreate a copy of all scorecards in draft modeThis recipe creates a draft scorecard for all existing scorecards.  It creates each scorecard with a suffix for the scorecard tag of “-draft”
and it appends “ Draft” to the end of the existing title.fortagin`cortexscorecardslist|jq-r".scorecards[].tag"`docortexscorecardsdescriptor-t${tag}|yq'.draft = true | .tag += "-draft" | .name += " Draft"'|cortexscorecardscreate-f-doneReplace scorecards with draft versions and delete the draft versionsThis recipe is a companion to the above recipe.  This recipe will replace the versions from
which the drafts were created and delete the drafts.fortagin`cortexscorecardslist-s|jq-r".scorecards[].tag"|grep"\-draft$"`docortexscorecardsdescriptor-t${tag}|yq'.draft = false | .tag |= sub("-draft","") | .name |= sub(" Draft", "")'|cortexscorecardscreate-f-&&cortexscorecardsdelete-t${tag}doneGet draft scorecards, change draft to false and save on diskThis recipe is similar to the one above, but it does not create a new scorecard in Cortex.  Rather, it makes the changes and saves to a file.fortagin`cortexscorecardslist-s|jq-r".scorecards[].tag"|grep"\-draft$"`docortexscorecardsdescriptor-t${tag}|yq'.draft = false | .tag |= sub("-draft","") | .name |= sub(" Draft", "")'>${tag}.yamldoneDelete all draft scorecardsWARNING: This recipe will delete all draft scorecards.fortagin`cortexscorecardslist-s|jq-r".scorecards[].tag"`docortexscorecardsdelete-t${tag}doneIf you only want to delete some drafts, for example if you followed a recipe that creates draft versions of all existing scorecards, you
will likely want to run this instead:fortagin`cortexscorecardslist-s|jq-r".scorecards[].tag"|grep"\-draft$"`docortexscorecardsdelete-t${tag}doneCompare scorecard scores and levels for two scorecardsThis could be helpful for changing CQL rules (for example for CQL v1 -> CQL v2) and ensuring that scorecards produce the same results.The following command get all scores for a scorecard, pipes the JSON output to jq and filters it to create a CSV file of the form:service,score,ladderLevelcortexscorecardsscores-tmyScorecard|jq-r'.serviceScores[] | [ .service.tag, .score.ladderLevels[].level.name // "noLevel", .score.summary.score|tostring] | join(",")'|sort>/tmp/scorecard-output.csvRun this command for two different scorecards and diff the csv files to compare resultsexportSCORECARD=scorecard1cortexscorecardsscores-t${SCORECARD}|jq-r'.serviceScores[] | [ .service.tag, .score.ladderLevels[].level.name // "noLevel", .score.summary.score|tostring] | join(",")'|sort>/tmp/${SCORECARD}.csvexportSCORECARD=scorecard2cortexscorecardsscores-t${SCORECARD}|jq-r'.serviceScores[] | [ .service.tag, .score.ladderLevels[].level.name // "noLevel", .score.summary.score|tostring] | join(",")'|sort>/tmp/${SCORECARD}.csvsdiff-s/tmp/scorecard1.csv/tmp/scorecard2.csvDelete all Workday teamsThis recipe is helpful if you want to remove all Workday teams and import from scratch.forteamin`cortexteamslist|jq-r'.teams[] | select (.type == "IDP") | select (.idpGroup.provider == "WORKDAY") | .teamTag'`docortexteamdelete-t${team}done