CLI tool for authenticating against the SAP Commerce Cloud v2 (CCV2) portal and running HAC operations. Uses IAS OAuth2 SSO via browser emulation — no OAuth tokens or API keys required.
This project is an independent open-source tool and is not affiliated with, endorsed by, or supported by SAP SE or its subsidiaries. SAP Commerce Cloud, SAP IAS, and related product names are trademarks of SAP SE.
Use of this tool is subject to your organization’s SAP service agreement. You are solely responsible for ensuring that your use complies with applicable terms of service.
MIT License. See LICENSE for details.
-
IAS OAuth2 SSO authentication with TOTP two-factor support
-
Encrypted credential vault (AES-256-GCM + Argon2id)
-
Session caching — skip re-auth for 1 hour
-
Multi-project / multi-subscription config (per-project YAML files)
-
Portal V1 API access: environments, services/aspects, replica routes
-
Interactive
config setupwizard — auto-downloads environments and aspects -
config refresh— re-fetches aspects and routes from the portal, updates config in place -
flexsearch— execute FlexibleSearch or direct SQL via HAC -
count— count items of a given type with optional WHERE clause -
enumcodes— list all codes for a SAP Commerce enum type -
groovy— execute Groovy scripts via HAC console -
loglevel— change Log4j logger levels at runtime -
cache clear— clear region cache across all nodes -
cronjobs— query CronJob execution statistics -
uptime— show node start time and uptime
git clone https://github.com/mmolotov/cx_hac_ccv2_helper
cd cx_hac_ccv2_helper
go build -o hac-helper .The fastest way to get started is the interactive setup wizard:
./hac-helper config setupThis will:
-
Prompt for project name, subscription alias, and CCV2 subscription ID
-
Prompt for vault master password and SAP credentials. It is used to store passwords locally in the encrypted file
-
Authenticate against the portal
-
Fetch all environments and their service aspects (including replica routes)
-
Let you confirm/override URLs for each aspect
-
Prompt for HAC credentials (global or per-environment)
-
Save per-project config and encrypted credentials
Config lives in .config/ relative to the working directory (where the binary is run).
Override the location with the HAC_HELPER_CONFIG_DIR environment variable.
Each project is stored in .config/projects/{project}.yaml. Generated automatically by config setup or config refresh, or create manually.
subscriptions:
t1: # subscription alias (used with --subscription flag)
subscription_id: "abc123" # CCV2 subscription ID from the portal
last_updated: 2026-03-03T12:00:00Z
environments:
d1:
code: d1
name: Development
aspects:
hcs_platform_backoffice:
code: hcs_platform_backoffice
name: Backoffice
url: https://backoffice.d1.my-project.model-t.cc.commerce.ondemand.com
context_path: /hac
routes:
- api-8477ccd75c-jwxwn
- api-8477ccd75c-kzmqp
hcs_storefront_web:
code: hcs_storefront_web
name: Storefront
url: https://store.d1.my-project.model-t.cc.commerce.ondemand.com
s1:
code: s1
name: Staging
aspects:
hcs_platform_backoffice:
code: hcs_platform_backoffice
name: Backoffice
url: https://backoffice.s1.my-project.model-t.cc.commerce.ondemand.comFields:
| Field | Description |
|---|---|
|
Arbitrary subscription alias, used with |
|
CCV2 subscription ID as shown in the portal |
|
Timestamp of last |
|
Environment code (e.g. |
|
Human-readable environment name |
|
Base URL for the aspect |
|
Optional URL context path (e.g. |
|
Replica names (used as |
Credentials are stored encrypted in .config/credentials.enc.
The vault is AES-256-GCM encrypted, key derived via Argon2id from a master password you choose. You are prompted for the master password when credentials are needed.
File layout: [4B magic='HACV'][16B salt][12B nonce][AES-256-GCM ciphertext]
The vault stores per-project/subscription:
-
sap_login/sap_password— SAP IAS credentials for portal authentication -
default_hac_login/default_hac_password— HAC credentials used for all environments -
environments.<code>.hac_login/hac_password— Per-environment HAC overrides (optional; fallback to default if absent)
All commands accept the following global flags:
| Flag | Default | Description |
|---|---|---|
|
|
Project name (as in config YAML) |
|
Subscription alias |
|
|
false |
Dump HTTP responses to stderr |
Interactive wizard. Authenticates against the portal, fetches all environments and service aspects (with replica routes), and saves the full configuration.
./hac-helper config setupRe-authenticates against the portal, re-fetches all environments and service aspects, and updates the config in place. Updates last_updated timestamp.
./hac-helper config refresh --project my-project --subscription t1A staleness warning is printed by HAC commands when last_updated is older than 24 hours:
[WARNING] Config for my-project/dev is 36 hours old — consider running: config refresh -p my-project -s t1
All auth subcommands require --project / -p and --subscription / -s flags.
Authenticate against the CCV2 portal. Uses cached session if valid; otherwise runs the full IAS OAuth2 SSO flow.
./hac-helper auth login -p my-project -s t1Flow:
-
Checks for a cached session (
.config/sessions/). If valid, exits immediately. -
Prompts for vault master password to load stored credentials.
-
If credentials not in vault, prompts for SAP email and password interactively.
-
Executes IAS OAuth2 SSO flow against
portal.commerce.ondemand.com. -
If 2FA (TOTP) is required, prompts for the one-time code.
-
Saves the session cookie jar for 1 hour.
Remove the cached session for a project/subscription.
./hac-helper auth logout -p my-project -s t1HAC commands connect directly to the HAC console of a specific environment aspect.
--project defaults to local, --subscription to t1, --environment to d1.
Multi-target commands (loglevel, cache, uptime, groovy, config get/set) default to all aspects; single-target commands (flexsearch, enumcodes, count, cronjobs) default to the backoffice aspect.
Execute a FlexibleSearch or direct SQL query via HAC.
./hac-helper flexsearch "SELECT {PK},{code} FROM {Product} WHERE {code} = 'mycode'"
# Read query from stdin
echo "SELECT {PK},{code} FROM {Product}" | ./hac-helper flexsearch
# Direct SQL
./hac-helper flexsearch --sql "SELECT * FROM products WHERE p_code = 'mycode'"
# CSV output
./hac-helper flexsearch "SELECT {PK} FROM {Product}" -f csvFlags:
| Flag | Default | Description |
|---|---|---|
|
|
Environment code |
|
|
Aspect containing HAC |
|
|
Path to HAC within the aspect URL |
|
false |
Execute as direct SQL instead of FlexibleSearch |
|
200 |
Maximum number of results |
|
|
Output format: |
|
Locale for query execution (e.g. |
|
|
0 |
Query timeout in milliseconds (0 = disabled) |
|
0 |
Cancel query timeout in milliseconds |
Count items of a given type via FlexibleSearch.
./hac-helper count Product
./hac-helper count Order --where "{status} = 'CREATED'"
./hac-helper count Product -e s1Executes: SELECT count({PK}) FROM {TypeCode} [WHERE condition]
Flags:
| Flag | Default | Description |
|---|---|---|
|
|
Environment code |
|
|
Aspect containing HAC |
|
|
Path to HAC within the aspect URL |
|
Optional WHERE clause (without the WHERE keyword) |
List all codes for a SAP Commerce enum type.
./hac-helper enumcodes OrderStatus
./hac-helper enumcodes -l de -f csv ArticleApprovalStatusFlags:
| Flag | Default | Description |
|---|---|---|
|
|
Environment code |
|
|
Aspect containing HAC |
|
|
Language for localized enum name |
|
|
Output format: |
Execute a Groovy script via the HAC console. Accepts a script string, file path, directory, or stdin.
./hac-helper groovy 'println spring.getBean("flexibleSearchService")'
# From file
./hac-helper groovy my-script.groovy
# All files in directory
./hac-helper groovy ./scripts/
# From stdin
echo 'println "hello"' | ./hac-helper groovy
# Target a specific node
./hac-helper groovy --node api-8477ccd75c-jwxwn my-script.groovy
# With database commit
./hac-helper groovy --commit my-script.groovyFlags:
| Flag | Default | Description |
|---|---|---|
|
|
Environment code |
|
|
Aspect(s) to target |
|
false |
Run on all configured aspects |
|
Pin to a specific cluster node (ROUTE cookie) |
|
|
false |
Commit database changes (default: rollback) |
Change Log4j logger levels at runtime across all targeted aspects.
./hac-helper loglevel de.hybris.platform.order=DEBUG
./hac-helper loglevel de.hybris.platform.order=DEBUG com.example.MyService=WARN
./hac-helper loglevel com.example.MyService=INFO -a backofficeValid levels: TRACE DEBUG INFO WARN ERROR FATAL OFF
Flags:
| Flag | Default | Description |
|---|---|---|
|
|
Environment code |
|
Aspect(s) to target (default: all) |
|
|
false |
Target all configured aspects |
Clear region cache on all targeted nodes.
./hac-helper cache clear
./hac-helper cache clear -a backoffice -e s1Flags:
| Flag | Default | Description |
|---|---|---|
|
|
Environment code |
|
Aspect(s) to target (default: all) |
|
|
false |
Target all configured aspects |
Show CronJob execution statistics. Requires one of --cronjob, --job, or --bean.
./hac-helper cronjobs --cronjob myBackofficeJob
./hac-helper cronjobs --job myJob --like
./hac-helper cronjobs --bean com.example.myBean --like -f csv
./hac-helper cronjobs -c myJob -e s1 --max-count 50Flags:
| Flag | Default | Description |
|---|---|---|
|
|
Environment code |
|
|
Aspect containing HAC |
|
Filter by CronJob code (exact match) |
|
|
Filter by Job code (exact match) |
|
|
Filter by ServiceLayerJob spring bean ID (exact match) |
|
|
false |
Use |
|
200 |
Maximum number of results |
|
|
Output format: |
Columns returned: job, cron_job, pk, status, result, start_time, end_time, duration_sec
Show start time and uptime for each targeted node.
./hac-helper uptime
./hac-helper uptime --format timestamp
./hac-helper uptime -a backoffice -a api -e s1Example output:
[backoffice] started=2026-03-10T08:42:11Z uptime=1d 2h 15m 30s [api] started=2026-03-10T08:45:03Z uptime=1d 2h 12m 38s
Flags:
| Flag | Default | Description |
|---|---|---|
|
|
Environment code |
|
Aspect(s) to target (default: all) |
|
|
false |
Target all configured aspects |
|
|
Output format: |
.config/ # relative to working directory (or HAC_HELPER_CONFIG_DIR)
├── projects/
│ ├── my-project.yaml # per-project config (environments, aspects, routes)
│ └── another-project.yaml
├── credentials.enc # AES-256-GCM encrypted SAP + HAC credentials
└── sessions/
├── my-project_dev.json # cached session (expires after 3600s)
└── my-project_prod.json
-
credentials.enc — AES-256-GCM encrypted. Key derived via Argon2id (time=1, mem=64MiB, threads=4). File permissions:
0600. -
sessions/ — plain JSON cookie files. Treat as sensitive. Permissions:
0600. -
The HTTP client skips TLS verification for HAC connections (self-signed certificates in CCV2).