ci-server-engineer/.claude/skills/audit-trail/tasks/read-audit-trail.md
cliu bf7d88a027 R1.05 re-check batch 3: alarms, audit, authorization, classes, HAC, reporting, pyTOOLS
Full manual diffs (L15, C20, E30, L25, J40, C10 §2, L10, P10, P11, J20,
C30, P20, R40, E10) and read-only checks on the shared R1.05 test server.
Skills and summaries moved to R1.05; new skill pytools (IM 36K10P40) from
docs (no Python on the test server). Issues ISS-132..181; corrections to
version-differences (E10, E30, P11, dss_ath_grp_u0104); C10 summary lists
the 3 new authorization actions; r105-verification V10-V17.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:21:36 +11:00

135 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
task: Read the audit trail (export, RQL query, audit report) and know what each tool records
version: R1.05 (first written for R1.03)
source: IM 36K10L25-01EN §1.1, §2.1.2, §3.1, App. 1 (4th ed., Feb. 2026); IM 36K10C50-01EN §2.22, §4.12 (Feb. 2026); IM 36K10G10-01EN ch. 9; R1.05 `tls\src\audit_trail.dss`; practiced on CI-Eng-Sample 2026-10-01
status: verified on R1.03 (2026-10-01); on the R1.05 test server 2026-10-09 (read-only) the dataset definition, an RQL read of the whole trail and the approval fields were checked; sample report CIENG_AUDIT loaded with 0 errors on 2026-10-08 (load check only, not generated)
---
# Read the audit trail
Read-only. Dataset `AUDIT_TRAIL` (storage group `ADT`); every field is read-only except
`APPLICATION_SUB` (the "modifiable ASCII application info") and `PROFILE`.
## 1. Fields
| Field | Content |
|---|---|
| `NAME` | `<ACTION_TIME>/<ACTION_STAMP>`, e.g. `01-OCT-26 17:05:00.181/84` |
| `ACTION_TIME`, `NOTIFICATION_TIME`, `MODIFICATION_TIME` | When it happened / reached AUDIT Service / `APPLICATION_SUB` was last changed |
| `SUBJECT_GROUP` | Subject: the **dataset name** for configuration and DSS value changes (`ITEM_DF`, `ITEM_VAL`, `SECTION_DF`, `REPORT_DF`, `AUDIT_EVENT_CLAS_DF` …) or a classifier subject (`CI-SERVER` for logins, `ITEM`, `SUB-ITEM` …) |
| `SUBJECT_ATTRIBUTE` | Changed field (`HIGH_LIMIT`, `ITEM_VALUE`, `DESCRIPTION` …); empty for insert/delete/login |
| `SUBJECT_ACTION` | `INSERT`, `MODIFY`, `DELETE`, `LOGIN`, `LOGOUT`, `LOGIN-ATTEMPT`, `ACKNOWLEDGE`, `SHELVE`, `UN-SHELVE` |
| `SUBJECT_SOURCE` | Tool that made the change (table in §2) |
| `SUBJECT_IDENT` | Record name: item, section, object (`<object>:<attribute>` for attribute values) … |
| `USER_NAME`, `PROFILE`, `TERMINAL` | CI Server user and profile; terminal often empty |
| `ACTION_NODE`/`ACTION_PROCESS`, `NOTIFICATION_NODE`/`NOTIFICATION_PROCESS` | Node and process (`DSSSDA00`, `JHMISET1086`, `DSSQLD00875` …) |
| `OLD_VALUE`, `NEW_VALUE` | Text, max 64 characters (longer values are cut) |
| `REASON`, `APPLICATION_INFO`, `APPLICATION_SUB` | Free text from the notifying program (empty in the tests) |
| `APPROVAL_REASON` (256), `APPROVER` (128) | **R1.05** (R1.04 and later): reason and approver name given with the change (see §1a); read-only, select only |
### 1a. Approval reason and approver (R1.04 and later)
Added for FDA 21 CFR Part 11 (the definition calls them *CPP* approval fields, a change to a
critical process parameter). IM 36K10L25 does not mention them (ISS-140); IM 36K10C50 does:
- An *Update item/parameter* action on a display (§4.12) can carry a **Reason** (≤ 256
characters) and an **Approver** (≤ 128 characters), typed in or taken from display parameters.
- Alarm acknowledgement with reason and approver (§2.22): either through an item parameter
(attribute *Acknowledged* = 1, item alarms only) or through the alarm overview's
*External Acknowledgement* properties (*Alarm Key*, *Approver*, *Reason*, *Trigger*). Building
the display: skill `graphics`, `create-display.md`.
Verified on the R1.05 test server (2026-10-09, read-only RQL): the fields exist in
`AUDIT_TRAIL`; 3 records out of about 15 500 had both filled, all `ITEM` `VALUE` `MODIFY` from
`OPER-INTERFACE` (an operator write), with `REASON` empty — so the reason goes to
`APPROVAL_REASON`, not to `REASON`. An alarm acknowledgement with reason / approver was **not
tested** (no such display; displays must not be changed on the shared server). Read them with:
```
column r as 'A40' heading 'Reason';
column p as 'A20' heading 'Approver';
select action_time, subject_group, subject_ident, subject_action, user_name, approver p,
approval_reason r
from audit_trail
where approver > ' ' or approval_reason > ' '
order by action_time;
```
(`> ' '` finds non-empty text; this `where` clause was run on R1.05 with a shorter column list.)
On R1.03 these fields do not exist and the query fails.
## 2. What is recorded (verified on R1.03.00)
| Action | Recorded as |
|---|---|
| `dssqld` load / modify / remove (any dataset) | `<DATASET>`, field, `INSERT`/`MODIFY`/`DELETE`, source **`ENT-ENG-MOD`**, user `FULL AUTHORIZATION`, plus a `CI-SERVER` `LOGIN`/`LOGOUT` pair per `dssqld` run (not `QUICKLOAD`) |
| Writing a value through DSS (`dssqld -m` on `ITEM_VAL`) | `ITEM_VAL` `ITEM_VALUE` `MODIFY`, old and new value — for **every** item, whatever its *Audit trailing wanted* (`AUDIT_INFO`) |
| Engineering Module: change an item field | `ITEM_DF` `<FIELD>` `MODIFY`, source `LOC-ENG-MOD`, user `ADMIN` (the logged-in user) |
| Engineering Module: right-click item › *Update value* | `ITEM_VAL` `ITEM_VALUE_STR` `MODIFY` (old/new) and `ITEM_VAL` `STATUS` `MODIFY`, source `LOC-ENG-MOD` |
| Engineering Module / Operator / OPC UA server login | `CI-SERVER` `LOGIN` / `LOGOUT`, source `LOC-ENG-MOD`, `OPER-INTERFACE`, `VIA-OPC-UAS` |
| Operator display write (button / input) on an item with *Audit trailing wanted* (`AUDIT_INFO` 1) | `ITEM` `VALUE` `MODIFY` `OPER-INTERFACE` (old/new) and `ITEM` `STATUS` `MODIFY`, user = operator; with `AUDIT_INFO` 0 **nothing** |
| `itmval -p` (ITEM Service API) | **nothing**, even with `AUDIT_INFO` 1 |
So `AUDIT_INFO` matters only for operator (and PROCESS) writes; DSS changes are always
audited. The `SUBJECT_SOURCE` of a user interface comes from its *audit
trail id* in `dssana.sup` `USER_INTERFACE` (Engineering Module = `LOC-ENG-MOD`).
**R1.05 additions** (ISS-141; classifiers verified 2026-10-09, behaviour not re-tested):
- Source `REST-SERVER`: the RESTful API (`jrstsrv`, skill `data-access`). The R1.05 test
server's trail holds `REST-SERVER` `LOGIN` / `LOGOUT` pairs and `MODIFY` records.
- Source `PYTOOLS`: the pyTOOLS Python module (IM 36K10P40). Not seen in the trail.
- Source `PASSWORD-CHECK`: the Edit Module *Password Check* function (IM 36K10C50 §2.31). Not seen.
- Action `PENDING` on `ITEM` `VALUE` / `STATUS`: per the R1.05 C header comments, for item writes
with a Vnet *on send* / *on receive* update policy (CENTUM). Not seen; not tested (no Vnet).
Sources seen in the R1.05 test server's trail (2026-10-09, about 15 500 records): `ENT-ENG-MOD`
(most: `dssqld`), `LOC-ENG-MOD`, `OPER-INTERFACE`, `REST-SERVER`, `ENT-EDIT-MOD`,
`LOC-EDIT-MOD`, `HMI`, `DSS-CLIENT`, `VIA-OPC-UAS`.
## 3. Export
`dssqld -e` skips `AUDIT_TRAIL` in a full export (`NO-EXPORT` in `dssqld.sup`); name it:
```
dssqld -e audit.qlo -d AUDIT_TRAIL
```
or filter (dates as `dd-mm-yyyy hh:mm:ss`, local time):
```
@FIELDS
NAME,SUBJECT_GROUP,SUBJECT_ATTRIBUTE,SUBJECT_ACTION,SUBJECT_SOURCE,SUBJECT_IDENT,USER_NAME,OLD_VALUE,NEW_VALUE
@SELECT
'SUBJECT_IDENT = "<Section>.<Tag>" AND ACTION_TIME > "01-10-2026 17:00:00"'
@AUDIT_TRAIL
```
`dssqld -e out.csv audit.qli -c` (CSV). **Keep `NAME` in `@FIELDS`**: without the key field the
export silently returns 0 records (verified). The whole trail can be large (5 000 records after a
year of test work). Wildcards: `SUBJECT_IDENT LIKE "<Section>.*"` (`*`, not `%`; `=` with `*`
matches nothing).
## 4. RQL query and audit report
```
column t as 'DD-MM-YYYY hh:mm:ss' heading 'Time';
select action_time t, subject_group, subject_attribute, subject_action, subject_source,
subject_ident, user_name, old_value, new_value
from audit_trail
where action_time > @date - 3600 and subject_ident like '<Section>.%'
order by action_time;
```
Use aliases with `COLUMN … AS 'A12'` to keep lines short (the fields are 16–256 characters
wide). Try it in the interactive generator (skill `reporting`, `rql-interactive.md`): put the
query in a file that starts with `set @next 0;` and `set @page_size 0;` and ends with `exit;`,
then `rptgen -s rptgen.rpt < q.rql > q.out` in `cmd` (verified on R1.05 2026-10-09: one
heading line, a `====` line, then one line per record; the echoed `RPT>` prompts appear in the
output file). The sample
report `CIENG_AUDIT` (`examples/CI-Eng-Sample/19_audit_df.qli`) lists the last hour of events on
`CI-Eng-Sample.*`; generate it like any ad-hoc report (`define-reports.md` §2). On R1.05 it
loaded with 0 errors (2026-10-08, reduced sample load); it was not generated there. Generated from
`dssqld` it is stored but not printed (`FSL-E-PRT_UNKUSER`, ISS-045).
In the Engineering Module, *Configuration › Reporting › Reports* holds the system reports
`AUDIT_TRAIL` and `UA_SERVER_AUDIT` (IM 36K10C30 App. 1). Generated there (as the logged-in
user) `CIENG_AUDIT` printed to `CIENG_FILE` and showed in the report viewer (checked by the user).