Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions Studio/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,27 @@ The **hackolade** user pre-configured inside the image has the following UID/GID

### Required directories (inside containers)

Hackolade reads and writes data to the following folders inside containers:
#### Pre-built `hackolade/hck-cli` image (recommended)

-**/home/hackolade/.config/Hackolade**: this folder (**appData**) is necessary for the proper operation of the application in containers and must be readable and writable by **hackolade** user.
-**/home/hackolade/Documents/HackoladeLogs**: this folder is where Hackolade Studio writes its logging information, which is useful in case of any issue and must be readable and writable by **hackolade** user.
- **/home/hackolade/Documents/data**: we recommend this folder that will be used for generated artifacts within containers but you can define it anywhere inside container filesystem as long as you make it persistent. It may contain models, documentation, sources for reverse-engineering, artifacts out of forward-engineering, etc... Instead of a relative path to the location where the container is run, you may reference an absolute path to the location of these files.
-[Optional]**/home/hackolade/.hackolade/options**: is where Hackolade reads user defined configurations like naming conventions, excel export options, custom properties, etc...
The image expects a **read-only root filesystem** with exactly two writable mounts:

- **`/data`** (persistent volume): license/userData under `/data/app`, plus logs, models, output, settings, and options
- **`/tmp`** (tmpfs): sockets, caches, and scratch files

See [`doc/getting-started-hck-cli.md`](./doc/getting-started-hck-cli.md) and [`compose.yml`](./compose.yml). Custom CAs use read-only PEM mounts and `NODE_EXTRA_CA_CERTS` / `SSL_CERT_FILE` — see [`doc/custom-certificates.md`](./doc/custom-certificates.md).

**Breaking change:** do not mount `/home/hackolade/.config` for the pre-built image; that path is no longer used for license state.

#### Custom-built `hackolade/studio` images

Older custom builds may still use the historical layout:

- `/home/hackolade/.config/Hackolade`: application data (**appData**) — must be readable and writable by the container user
- `/home/hackolade/Documents/HackoladeLogs`: logging information
- `/home/hackolade/Documents/data`: generated artifacts (models, documentation, RE/FE outputs, etc.)
- [Optional] `/home/hackolade/.hackolade/options`: user-defined configurations

Prefer migrating custom images to the `/data` + `/tmp` model used by `hackolade/hck-cli`.


You must create manually the folders you will bind mount prior to running hackolade studio containers because docker doesn't create them automatically anymore.
Expand Down
149 changes: 104 additions & 45 deletions Studio/doc/getting-started-hck-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,20 +95,29 @@ The image uses `hck-cli` as its default entrypoint - a simple binary that execut

### Data Volume Structure

The image uses a simplified data structure with volumes mounted directly under `/data`:
The image is designed for a **read-only root filesystem**. Runtime writes go to exactly two places:

| Mount | Purpose |
| --- | --- |
| `/data` | Persistent volume: license/userData (`/data/app`), logs, models, output, settings, options |
| `/tmp` | tmpfs: sockets, caches, and scratch files (discarded when the container exits) |

Layout under `/data`:

- `/data/app` - Application data (license state, Electron userData). Lives on the `/data` volume via `XDG_CONFIG_HOME`.
- `/data/models` - Your input model files
- `/data/output` - Generated artifacts (documentation, schemas, etc.)
- `/data/logs` - Application logs organized in `<date>-command` folders (e.g., `2024-01-15-genDoc`) for per-command isolation and troubleshooting
- `/data/options` - (Optional) User-defined configurations
- `/data/settings` - Optional settings

**⚠️ MANDATORY:** The application data folder (`/home/hackolade/.config`) **MUST** be mounted as a volume. This volume is absolutely required for licensing and configuration to work properly. Without this volume mounted, the CLI will not function correctly.
**⚠️ MANDATORY:** Mount a volume at `/data` **and** a writable `/tmp` (tmpfs recommended). Without `/data`, licensing and configuration will not persist. Without `/tmp`, Electron and scratch I/O will fail under `read_only: true`.

This structure reduces path length and simplifies volume management compared to the previous `/home/hackolade/Documents/...` structure.
**Breaking change:** Earlier releases required a separate volume at `/home/hackolade/.config`. That path is no longer written; migrate the named volume to `/data` (license state is under `/data/app`).

**Volume validation:** The CLI automatically validates that required volumes are properly mounted. If a required volume is missing, the CLI will display a warning message to help you identify and fix the issue before command execution fails.
**Volume validation:** The CLI automatically validates that required mounts are writable. If a required mount is missing, the CLI will display a warning (or fail in the official image) before command execution.

**Log isolation:** Logs are automatically organized per command in `/data/logs` using folders named `<date>-command` (e.g., `2024-01-15-genDoc`, `2024-01-15-forweng`). This folder structure provides proper command isolation, making it easier to analyze logs for specific commands when troubleshooting issues. Each command execution creates its own log folder, allowing you to trace problems to specific operations by date and command type.
**Log isolation:** Logs are automatically organized per command in `/data/logs` using folders named `<date>-command` (e.g., `2024-01-15-genDoc`, `2024-01-15-forweng`). This folder structure provides proper command isolation, making it easier to analyze logs for specific commands when troubleshooting issues.

## Quick start with Docker Compose

Expand Down Expand Up @@ -293,58 +302,65 @@ If you prefer using Docker CLI directly instead of Docker Compose, here's how:
### Basic Command Structure

```bash
docker run --rm \
-v hackolade-studio-app-data:/home/hackolade/.config \
-v hackolade-studio-logs:/data/logs \
docker run --rm --read-only \
--cap-drop=ALL --security-opt=no-new-privileges \
--user 1000:1001 \
-v hackolade-studio-data:/data \
-v ${PWD}/models:/data/models \
-v hackolade-studio-output:/data/output \
--tmpfs /tmp:rw,size=1g,mode=1777 \
hackolade/hck-cli:8.9.2 COMMAND [OPTIONS]
```

### Create Required Volumes

First, create the named volumes:
First, create the named volume for persistent state:

```bash
docker volume create hackolade-studio-app-data
docker volume create hackolade-studio-logs
docker volume create hackolade-studio-output
docker volume create hackolade-studio-data
```

`/tmp` should be a tmpfs (shown above), not a named volume.

### Example Commands

**Check version:**
```bash
docker run --rm \
-v hackolade-studio-app-data:/home/hackolade/.config \
docker run --rm --read-only \
--user 1000:1001 \
-v hackolade-studio-data:/data \
--tmpfs /tmp:rw,size=1g,mode=1777 \
hackolade/hck-cli:8.9.2 version
```

**Get computer ID:**
```bash
docker run --rm hackolade/hck-cli:8.9.2 getComputerId
docker run --rm --read-only \
--user 1000:1001 \
-v hackolade-studio-data:/data \
--tmpfs /tmp:rw,size=1g,mode=1777 \
hackolade/hck-cli:8.9.2 getComputerId
```

**Generate documentation:**
```bash
docker run --rm \
-v hackolade-studio-app-data:/home/hackolade/.config \
-v hackolade-studio-logs:/data/logs \
docker run --rm --read-only \
--user 1000:1001 \
-v hackolade-studio-data:/data \
-v ${PWD}/models:/data/models \
-v hackolade-studio-output:/data/output \
--tmpfs /tmp:rw,size=1g,mode=1777 \
hackolade/hck-cli:8.9.2 genDoc \
--format=HTML \
--model /data/models/model.json \
--doc /data/output/doc.html
```
In case of offline validation:
```bash
docker run --rm \
-v hackolade-studio-app-data:/home/hackolade/.config \
-v hackolade-studio-logs:/data/logs \
docker run --rm --read-only \
--user 1000:1001 \
-v hackolade-studio-data:/data \
-v ${PWD}/models:/data/models \
-v hackolade-studio-output:/data/output \
-v ${PWD}/LicenseFile.xml:<Path used during validateKey>/LicenseFile.xml \
-v ${PWD}/LicenseFile.xml:/data/LicenseFile.xml:ro \
--tmpfs /tmp:rw,size=1g,mode=1777 \
hackolade/hck-cli:8.9.2 genDoc \
--format=HTML \
--model /data/models/model.json \
Expand Down Expand Up @@ -509,30 +525,28 @@ chown -R 1000:1001 ./models
chown -R 1000:1001 ./output
```

**Note:** The container runs as user `hackolade` with UID 1000 and GID 1001 (data-modelers group).
**Note:** The container runs as numeric user `1000:1001` by default (compatible with Kubernetes `runAsNonRoot`). OpenShift-style arbitrary UIDs in group 0 are also supported when `/data` is group-writable.

**Note:** Docker named volumes (like `hackolade-studio-app-data`) don't require permission changes on the host.
**Note:** Docker named volumes (like `hackolade-studio-data`) don't require permission changes on the host. Bind mounts for models should be owned by UID 1000 (or writable by group 0).

### Volume Not Found

If Docker says a volume doesn't exist, create it:

```bash
docker volume create hackolade-studio-app-data
docker volume create hackolade-studio-logs
docker volume create hackolade-studio-output
docker volume create hackolade-studio-data
```

Or let Docker Compose create them automatically on first run.
Or let Docker Compose create it automatically on first run. Ensure every run also mounts a writable `/tmp` (compose uses `tmpfs`).

### Volume Validation Warnings

The CLI automatically checks for required volumes and will warn you if they're not properly mounted. If you see warnings about missing volumes:
The CLI automatically checks for required writable mounts and will warn you if they're not properly mounted. If you see warnings about missing mounts:

1. **Check your compose.yml or docker run command** - Ensure all required volumes are defined:
- `hackolade-studio-app-data` → `/home/hackolade/.config` ⚠️ **MANDATORY** - Required for licensing and configuration
- `hackolade-studio-logs` → `/data/logs` (recommended for log isolation)
- `hackolade-studio-output` → `/data/output` (required for output operations)
1. **Check your compose.yml or docker run command** - Ensure:
- `hackolade-studio-data` → `/data` ⚠️ **MANDATORY** - license state, logs, output, settings
- tmpfs (or equivalent) → `/tmp` ⚠️ **MANDATORY** under `read_only: true`
- Optional bind: host `models` → `/data/models`

2. **Verify volumes exist:**
```bash
Expand All @@ -544,9 +558,9 @@ The CLI automatically checks for required volumes and will warn you if they're n
docker inspect <container-name> | grep -A 10 Mounts
```

4. **Review the warning message** - The CLI will indicate which specific volume is missing and what it's used for.
4. **Review the warning message** - The CLI will indicate which specific mount is missing and what it's used for.

**Important:** The `/home/hackolade/.config` volume is **MANDATORY** and must be mounted for the CLI to function. While the CLI will warn about missing volumes, operations will fail without the application data volume. For proper functionality and log isolation, mount all volumes as shown in the compose examples.
**Important:** A single `/data` volume plus `/tmp` tmpfs replaces the older multi-volume layout (`/home/hackolade/.config`, separate logs/output volumes). Migrate by mounting your persistent state at `/data`.

### License Validation Failed

Expand Down Expand Up @@ -672,19 +686,64 @@ docker compose run --rm hck-cli COMMAND [OPTIONS]
docker pull hackolade/hck-cli:8.9.2

# Create volumes
docker volume create hackolade-studio-app-data
docker volume create hackolade-studio-logs
docker volume create hackolade-studio-output
docker volume create hackolade-studio-data

# Run command
docker run --rm \
-v hackolade-studio-app-data:/home/hackolade/.config \
-v hackolade-studio-logs:/data/logs \
docker run --rm --read-only \
--user 1000:1001 \
-v hackolade-studio-data:/data \
-v ${PWD}/models:/data/models \
-v hackolade-studio-output:/data/output \
--tmpfs /tmp:rw,size=1g,mode=1777 \
hackolade/hck-cli:8.9.2 COMMAND
```

## Kubernetes Job (restricted / read-only rootfs)

A minimal Job that matches the compose hardening defaults (`readOnlyRootFilesystem`, non-root, dropped capabilities, `/data` PVC + `/tmp` emptyDir memory):

```yaml
# See also: k8s/hck-cli-job.yaml in this repository
apiVersion: batch/v1
kind: Job
metadata:
name: hck-cli-version
spec:
template:
spec:
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1001
fsGroup: 0
seccompProfile:
type: RuntimeDefault
containers:
- name: hck-cli
image: hackolade/hck-cli:8.9.2
args: ["version"]
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: data
mountPath: /data
- name: tmp
mountPath: /tmp
volumes:
- name: data
persistentVolumeClaim:
claimName: hck-cli-data
- name: tmp
emptyDir:
medium: Memory
sizeLimit: 1Gi
```

Apply the full example (including a PVC) from [`k8s/hck-cli-job.yaml`](../k8s/hck-cli-job.yaml).

## Backward compatibility with other images

For users migrating from the `hackolade/studio` image or custom-built images that use `startup.sh` as the entrypoint, this image maintains backward compatibility by including the `startup.sh` and `show-computer-id.sh` scripts.
Expand Down
4 changes: 4 additions & 0 deletions Studio/doc/license-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ docker run --rm \
--identifier=YOUR-UUID-FROM-STEP-1
```

For the pre-built `hackolade/hck-cli` image, mount a single `/data` volume (license state lives under `/data/app`) and a `/tmp` tmpfs instead of `/home/hackolade/.config/Hackolade`. See [`getting-started-hck-cli.md`](./getting-started-hck-cli.md) and [`compose.yml`](../compose.yml).

Replace:
- `YOUR-LICENSE-KEY` with your actual floating license key
- `YOUR-UUID-FROM-STEP-1` with the UUID you copied from step 1
Expand Down Expand Up @@ -114,6 +116,8 @@ docker run --rm \
--file=/LicenseFile.xml
```

With `hackolade/hck-cli`, prefer `-v hackolade-studio-data:/data` and mount the license file under `/data/...` (see [`getting-started-hck-cli.md`](./getting-started-hck-cli.md)).

Replace `YOUR-LICENSE-KEY` with your actual license key.

**Important:**
Expand Down
57 changes: 57 additions & 0 deletions Studio/k8s/hck-cli-job.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Example Kubernetes Job for hackolade/hck-cli with a read-only root filesystem.
# Requires a PVC (or other volume) at /data and a memory emptyDir at /tmp.
#
# kubectl apply -f hck-cli-job.yaml
#
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: hck-cli-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
---
apiVersion: batch/v1
kind: Job
metadata:
name: hck-cli-version
spec:
backoffLimit: 1
template:
metadata:
labels:
app: hck-cli
spec:
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1001
fsGroup: 0
seccompProfile:
type: RuntimeDefault
containers:
- name: hck-cli
image: hackolade/hck-cli:8.9.2
args: ["version"]
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: data
mountPath: /data
- name: tmp
mountPath: /tmp
volumes:
- name: data
persistentVolumeClaim:
claimName: hck-cli-data
- name: tmp
emptyDir:
medium: Memory
sizeLimit: 1Gi