Version 0.5.1 | From unzipping to your first real scan
Who this is for: you, as the first user, testing on your own laptop. It assumes you know ASE well and Python only a little.
Suggested path (about 1 to 2 hours):
ase-health ping.Licence: a customer build of the tool only runs when
a valid licence file is installed in your .ase-health
folder; otherwise it quits (exit code 3). A 14-day trial is simply a
short licence file that we email you on request: install the tool, run
ase-health licence request, email the text it prints to
hello@solverelay.com, then ase-health licence install FILE
(section 20). Developer builds without a built-in key run unrestricted
with a warning.
Honest status: the logic is covered by 60 automated tests, but the SQL that talks to ASE has been tested only against a simulated connection, never a real ASE server. Expect some queries to need adjusting on your version. Section 17 lists what is unverified.
ase-health reads metadata and statistics from an
SAP/Sybase ASE server, stores a snapshot, applies a set of rules, and
produces reports:
It is read-only. It runs only SELECT statements (Appendix A lists every one, and a test enforces this). It never changes the server, never reads your business tables, and sends nothing over the network except to your ASE server. The optional AI explanation (section 16) is off by default.
It is deterministic. The same snapshot always gives the same findings. Every finding carries the evidence behind it.
| Item | Needed for | Notes |
|---|---|---|
| Laptop: Windows 10/11, Linux or macOS | everything | 4 GB free RAM is plenty; the tool itself is tiny |
| Python 3.11 or newer | everything | Check with python --version |
| pip | installing | Comes with Python |
The zip file ase-health-v0.5.1.zip |
everything | |
| A text editor | editing the config file | Notepad is fine; VS Code is nicer |
| A web browser | viewing HTML reports | |
| For a real server only: an ASE server you may legally and safely test against | sections 5 to 6 | See 5.1 |
| For a real server only: pyodbc | connecting | Installed with pip install -e ".[db]" |
| For a real server only: an ODBC driver (SAP ASE ODBC driver, or FreeTDS) | connecting | See 5.2 |
For a real server only: isql (ships with ASE
or its client) |
creating the login, cross-checking results | |
| Excel or LibreOffice | opening the CSV | optional |
Sections 3 and 4 need only the first six rows. You can do them today without any database.
C:\work.
You should get C:\work\ase-health.unzip ase-health-v0.5.1.zip -d ~/workOpen a terminal (PowerShell on Windows) in the
ase-health folder. It contains pyproject.toml,
src, tests, samples and
docs.
python --version # Windows (try "py --version" if this fails)
python3 --version # Linux/macOS
You need 3.11 or higher. If you have less or nothing:
sudo apt install python3 python3-venv python3-pipbrew install pythonThis keeps the tool’s packages separate from the rest of your system.
Windows PowerShell:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
If PowerShell refuses with “running scripts is disabled”, run this once in that window and retry:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned
Linux/macOS:
python3 -m venv .venv
source .venv/bin/activate
Your prompt should now start with (.venv).
Re-activate this each time you open a new terminal.
pip install -e .
This installs the tool and its one dependency (click).
The -e means “editable”: if you change a rule in the
source, the change is live immediately. This step needs internet access
to fetch click.
ase-health --help
python -m unittest discover tests
You should see the command list, then
Ran 60 tests ... OK. If ase-health is “not
found”, your virtual environment is not active; as a fallback use
python -m ase_health.cli --help.
If you received a customer build, install your licence first
(section 20); every command except licence quits without
one.
The samples folder holds a made-up server called
DEMO_PROD with deliberate problems, so every rule has something to
find.
python samples/make_demo_history.py
This creates demo_history.db with six weekly
snapshots.
ase-health report --server DEMO_PROD --db demo_history.db
You get a Markdown report in the terminal: a summary line, “Fix these first”, then one block per finding. Try the other formats:
ase-health report --server DEMO_PROD --db demo_history.db --format summary
ase-health report --server DEMO_PROD --db demo_history.db --format summary-html --out summary.html
ase-health report --server DEMO_PROD --db demo_history.db --format html --out full.html
ase-health report --server DEMO_PROD --db demo_history.db --format csv --out findings.csv
Open summary.html in a browser. That is the page you
would give a manager. Use the browser’s Print to PDF to make a
PDF.
ase-health history --db demo_history.db # what is stored
ase-health rules # the rule IDs
ase-health queries # every SQL statement the tool can run
ase-health config --out my.toml # all thresholds, with defaults
Edit my.toml, delete everything except these lines and
save:
[txn]
medium_after_hours = 0.2
high_after_hours = 12
Then:
ase-health report --server DEMO_PROD --db demo_history.db --config my.toml
The long-transaction finding drops from HIGH to MEDIUM, and the
report header says which settings were customised. Now deliberately
break it (change medium_after_hours to
medium_after_hour) and see the clear error. The tool never
silently ignores a typo.
Delete demo_history.db when you are done. It is only
demo data.
Use a non-production server you are allowed to access. Options:
Whatever you use, create a few user databases with some data so the checks have something to look at. Deliberately create the situations the rules look for (see section 13), so you can see the tool catch them.
The tool connects through ODBC. Install pyodbc into your virtual environment:
pip install -e ".[db]"
(The quotes matter in PowerShell and zsh.)
You also need an ODBC driver for ASE. Two routes:
Route A: SAP’s ASE ODBC driver (Windows, or Linux if you have the client/SDK installed). It is part of the ASE client/SDK install. Afterwards, open ODBC Data Source Administrator (64-bit) on Windows and look at the Drivers tab for the exact driver name. It is typically something like “Adaptive Server Enterprise” but use whatever name you see. Python and the driver must both be 64-bit (or both 32-bit).
Route B: FreeTDS (free, common on Linux).
sudo apt install unixodbc freetds-bin tdsodbc # Debian/Ubuntu
odbcinst -q -d # should list [FreeTDS]
If FreeTDS is not listed, register it in
/etc/odbcinst.ini:
[FreeTDS]
Description = FreeTDS
Driver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so
(the path differs by distribution; dpkg -L tdsodbc shows
it). On Windows, FreeTDS needs a separate build and is less convenient;
prefer Route A there.
Find your server’s host and port (default often 5000, but check your interfaces/sql.ini file).
FreeTDS:
DRIVER={FreeTDS};SERVER=myhost;PORT=5000;UID=ase_health_ro;PWD=YourPassword;TDS_Version=5.0
SAP driver (adjust the driver name to what you saw):
DRIVER={Adaptive Server Enterprise};server=myhost;port=5000;db=master;uid=ase_health_ro;pwd=YourPassword
If the password contains ; or }, wrap it in
braces: PWD={pa;ss}.
Put the string in an environment variable so it never appears in command lines or scheduled-task definitions:
Linux/macOS:
read -s -p "ASE password: " PW; echo
export ASE_CONN="DRIVER={FreeTDS};SERVER=myhost;PORT=5000;UID=ase_health_ro;PWD=$PW;TDS_Version=5.0"
Windows PowerShell (the typed password is visible; use a throwaway test login):
$pw = Read-Host "ASE password"
$env:ASE_CONN = "DRIVER={Adaptive Server Enterprise};server=myhost;port=5000;db=master;uid=ase_health_ro;pwd=$pw"
The variable lasts for that terminal session. For permanent storage on a real deployment use the operating system’s secret mechanisms, not a text file.
Do not use sa. In isql, as an
administrator:
use master
go
sp_addlogin ase_health_ro, "ChangeMe_123!", master
go
-- repeat for every user database you want checked (needed for the
-- statistics and orphan-user checks, which query each database):
use orders
go
sp_adduser ase_health_ro
go
Do not grant sa_role, sso_role or mon_role. The tool needs none of them today.
What I could not verify: the exact minimum
permissions each query needs on every ASE version. Most system tables
are readable by public, but lct_admin,
syslogshold and the per-database tables may differ by
version and configuration. The next step tells you exactly which checks
work; any that do not will show as a warning, and you can then grant the
minimum needed (or accept the limitation). Please record what you find
in the test log. It becomes your “permissions required” page for
clients.
ase-health pingase-health ping
(ASE_CONN is read automatically.) Good output:
Connected. Adaptive Server Enterprise/16.0 SP03 PL08 ...
databases=7 config_values=... sa_role_holders=2 db_sizes=7 log_usage=7 ...
All collector queries ran.
If some checks cannot run you see WARNING: ... lines and
exit code 1. That is useful information, not a failure: it shows which
SQL needs fixing for your version or which permission is missing. See
section 14 for each message.
ase-health scan --label TESTBOX1
This stores a snapshot in ase_health.db in the current
folder. The label is the key under which history is
kept, so use the same label every time for the same server. Then:
ase-health report --server TESTBOX1
ase-health report --server TESTBOX1 --format summary-html --out summary.html
Run scan again a few times over several days. Trend and
“since the previous scan” features need history: the growth rule needs
at least 3 snapshots spanning 7 days. To see it sooner, lower
trend.min_span_days in a config file while testing.
Severity: INFO, LOW, MEDIUM, HIGH, CRITICAL.
Priority orders the “Fix these first” list. It is
(severity + 1) x exposure x 10 / effort, where exposure (1
to 3) is how widely the problem reaches and effort (1 to 3) is how hard
it is to fix. A quick, widely exposed problem can therefore outrank a
harder, higher-severity one. That is deliberate.
A finding contains:
LOG001.Header line: scan time, tool version, rules version. Always quote the rules version if you report a problem.
Custom settings and Collector warnings appear near the top when relevant. A report with collector warnings may be missing checks.
Time zones: collected_at is stored in
UTC. Age checks (dump age, open transactions) use the server’s own
clock, read from getdate(), because ASE stores times
without a time zone.
--format summary-html (print to PDF from the browser) or
--format summary (Markdown for email). It shows:
Default status logic: RED at 1 or more CRITICAL or 3 or more HIGH;
AMBER at 1 or more HIGH or 3 or more MEDIUM (or any CRITICAL); otherwise
GREEN. All of these are settings under [summary].
Suggested owners come from the OWNER table in
src/ase_health/summary.py. They are guesses; edit them to
match your organisation.
--format csv writes one row per finding.
ase-health export --out fleet.csv writes the latest
findings of every server in the history file.
| Column | Meaning |
|---|---|
| server, collected_at | which server and when |
| rule_id, severity, priority | what, how bad, fix order |
| title, affected, why_it_matters, recommended_fix | the finding |
| effort, exposure | effort label; exposure 1 to 3 |
| evidence_json | the data behind the finding |
| suggested_owner | from the OWNER table |
| owner, status, due_date, notes | blank tracking columns (status starts as “Open”) |
In Excel use Data > From Text/CSV and choose UTF-8 if
accented characters look wrong. Cells that start with =,
+, - or @ get an apostrophe added
on purpose: object names come from the database, and this stops a
malicious name from running as a spreadsheet formula.
Generate a template, edit, and pass it with
--config:
ase-health config --out my.toml
ase-health report --server TESTBOX1 --config my.toml
Delete any line to use its default.
disabled_rules = ["STA001"] switches a rule off. The tool
refuses unknown keys, non-numbers, out-of-range values, and inconsistent
pairs (for example a HIGH threshold at or below its MEDIUM
threshold).
| Setting (section and key in the file) | Default | Meaning |
|---|---|---|
[version] warn_months |
18 | warn this many months before end of mainstream maintenance |
[security] max_sa_role_holders |
3 | flag when more logins than this hold sa_role |
[security] min_password_length |
8 | flag when ‘minimum password length’ is below this |
[backup] max_log_dump_age_days |
7 | flag user databases with no log dump for this many days |
[trend] min_snapshots |
3 | snapshots needed before growth is projected |
[trend] min_span_days |
7 | days of history needed before growth is projected |
[trend] medium_growth_pct_30d |
10 | MEDIUM if projected 30-day growth reaches this percent |
[trend] high_growth_pct_30d |
25 | HIGH if projected 30-day growth reaches this percent |
[log] high_below_free_pct |
20 | HIGH if free log space is below this percent |
[log] critical_below_free_pct |
10 | CRITICAL if free log space is below this percent |
[txn] medium_after_hours |
1 | MEDIUM if a transaction has been open this many hours |
[txn] high_after_hours |
4 | HIGH if a transaction has been open this many hours |
[stats] max_age_days |
30 | flag table statistics older than this many days (LOW; MEDIUM at 3x) |
[stats] min_table_rows |
10000 | ignore tables smaller than this many rows |
[conn] medium_above_pct |
80 | MEDIUM if connections exceed this percent of the limit |
[conn] high_above_pct |
95 | HIGH if connections exceed this percent of the limit |
[summary] top_risks |
5 | how many risks the management summary lists |
[summary] red_if_critical_at_least |
1 | overall status RED at this many CRITICAL findings |
[summary] red_if_high_at_least |
3 | overall status RED at this many HIGH findings |
[summary] amber_if_high_at_least |
1 | overall status AMBER at this many HIGH findings |
[summary] amber_if_medium_at_least |
3 | overall status AMBER at this many MEDIUM findings |
Note: DB003 (offline databases) is produced by rule
DB002; to disable both use "DB002".
ase_health.db is a single SQLite file in the folder
where you run scan (change with --db). It
holds one row per snapshot per server.
ase-health history # servers, counts, first and last scan
ase-health prune --days 365 # delete snapshots older than a year
ase-health load old_snapshot.json # import JSON snapshots
Trend features need regular snapshots. Schedule scan,
nothing else.
Linux cron (daily at 06:30; put
ASE_CONN in a file readable only by the user,
e.g. chmod 600 ~/.ase_env):
30 6 * * * . ~/.ase_env && cd ~/work/ase-health && .venv/bin/ase-health scan --label PROD1 >> scan.log 2>&1
Windows Task Scheduler: create a basic task that runs daily, action Start a program:
C:\work\ase-health\.venv\Scripts\ase-health.exescan --label PROD1C:\work\ase-healthSet ASE_CONN as a user environment variable (System
Properties > Environment Variables) for the account that runs the
task. Be aware that this stores the password in that account’s
environment, so use a restricted login on a protected machine.
Use in automation:
ase-health report --server PROD1 --fail-on CRITICAL exits
with code 1 if any finding is at or above that level.
All thresholds below are defaults; see section 9.
| ID | What it checks | Data source | Severity logic |
|---|---|---|---|
| VER001 | Version against end of mainstream maintenance | @@version and a table in
rules/core.py |
HIGH if the date has passed; MEDIUM within 18 months; INFO beyond. Versions older than 15.7: CRITICAL |
| CFG001 | Direct updates to system tables enabled | sysconfigures |
CRITICAL if on |
| CFG002 | Auditing disabled | sysconfigures |
MEDIUM if off |
| CFG003 | Minimum password length below 8 | sysconfigures |
MEDIUM |
| SEC001 | More than 3 logins hold sa_role | syslogins, sysloginroles,
syssrvroles |
HIGH |
| SEC002 | Database users with no server login | per-database sysusers, sysprotects,
master..syslogins |
LOW; MEDIUM if any has explicit permissions |
| DB001 | trunc log on chkpt on user databases |
sysdatabases.status bit 8 |
HIGH |
| DB002 | Suspect databases (and DB003: offline) | status bit 256; status2 bit 16 |
CRITICAL (suspect); LOW (offline) |
| BKP001 | No log dump for more than 7 days | sysdatabases.dumptrdate |
HIGH |
| TRD001 | Allocated database size growing 10%+ per 30 days | sysusages, stored history |
MEDIUM; HIGH at 25%+ |
| LOG001 | Transaction log nearly full | sysusages log segment, lct_admin |
HIGH below 20% free; CRITICAL below 10% |
| TXN001 | Transactions open too long | syslogshold |
MEDIUM over 1 hour; HIGH over 4 hours |
| STA001 | Stale statistics on large tables | per-database systabstats |
LOW; MEDIUM if older than 3x the limit |
| CON001 | Connection limit nearly reached | sysprocesses,
number of user connections |
MEDIUM above 80%; HIGH above 95% |
Known caveats per rule
EOMM table.sysusages), not used space. It detects repeated space
additions, but will not notice data growing inside a fixed-size
database. Treat it as experimental; improving it (using used-space
figures) is planned.Run ase-health scan, then for each row run the native
command in isql and compare with the
Evidence line of the report. Record results in Appendix
C.
| Rule | Cross-check in isql | Make it fire (on a test server only) |
|---|---|---|
| VER001 | select @@version |
none needed |
| CFG001 to CFG003 | sp_configure "allow updates",
sp_configure "auditing",
sp_configure "minimum password length" |
change the setting temporarily, rescan |
| SEC001 | sp_displaylogin <login> for each reported
name |
sp_role "grant", sa_role, <test_login> |
| SEC002 | sp_helpuser in each database |
drop a login that still has a user in a test database |
| DB001 | sp_helpdb <db> (look at the status/options) |
sp_dboption <db>, "trunc log on chkpt", true |
| DB002/DB003 | sp_helpdb |
take a test database offline |
| BKP001 | select name, dumptrdate from master..sysdatabases |
do not dump a test database’s log for 8 days, or lower
max_log_dump_age_days to 0 |
| TRD001 | select db_name(dbid), sum(size) from master..sysusages group by dbid |
extend a test database repeatedly and scan weekly |
| LOG001 | sp_spaceused syslogs inside the database |
fill a small test log without dumping it |
| TXN001 | select * from master..syslogshold,
sp_who |
open a transaction (begin tran) and leave it |
| STA001 | optdiag statistics <db>..<table> |
create a big table and never update its statistics |
| CON001 | sp_monitorconfig "number of user connections" |
open many sessions, or lower the connection limit on a test server |
For each row record: did the tool’s number match
ASE’s? If not, copy the SQL from ase-health queries, run it
in isql, and note the difference (wrong column, different
units, permission). Those notes are exactly what is needed to fix the
collectors.
| Symptom | Likely cause and fix |
|---|---|
python not recognised /
python3: command not found |
Python missing or not on PATH. Reinstall and tick Add to
PATH (Windows); try py instead of
python |
| pip says the package requires a newer Python | You have Python older than 3.11. Install a newer one and recreate the virtual environment |
ase-health: command not found |
The virtual environment is not active. Activate it again, or use
python -m ase_health.cli ... |
| PowerShell: running scripts is disabled | Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned,
then activate again |
pyodbc not installed |
pip install -e ".[db]" inside the activated
environment |
libodbc.so.2: cannot open shared object file |
Install unixODBC: sudo apt install unixodbc |
IM002 Data source name not found and no default driver specified |
The driver name in DRIVER={...} does not match an
installed driver. List them (odbcinst -q -d, or the Drivers
tab on Windows) and copy the exact name. Also check 32 vs 64-bit
mismatch |
| Login failed | Wrong user/password, or the login cannot reach the default database.
Test the same login in isql |
| Timeout or cannot connect | Wrong host or port, firewall, or ASE not running. Confirm the port in the interfaces/sql.ini file |
| FreeTDS protocol errors | Add TDS_Version=5.0 to the connection string |
WARNING: <check>: ... Invalid column name / Invalid object name / unknown function |
The SQL differs on your ASE version. Run
ase-health queries, test that statement in
isql, and note the exact error for fixing |
WARNING: ... permission denied |
The monitoring login lacks SELECT or EXECUTE on that object. Grant the minimum needed, or accept that the rule will not run |
WARNING: server_time |
getdate() failed; age checks fall back to UTC and may
be off by your time-zone offset |
WARNING: <db>: skipped (unusual database name) |
The database name has characters the tool refuses to put into SQL. Rename it or ignore that database |
No stored snapshots for X |
The --server label does not match. Run
ase-health history to see labels, and check
--db points to the right file |
Unknown setting 'x.y' or other config errors |
Read the message; run ase-health config to see valid
keys |
| Growth rule never fires | It needs 3 snapshots over 7 days, and it measures allocated size only |
| Excel shows odd characters | Import with Data > From Text/CSV, encoding UTF-8 |
| Cells start with an apostrophe | By design; it prevents formula injection |
No licence file found / exit code 3 |
Install a licence: section 20 |
The licence file is not valid: ... different installation |
The file was issued for another Installation ID (or you deleted
.ase-health). Run licence request again |
If you hit something not listed, copy the full error text and the
output of ase-health ping. Remove server and login names
first if you share it.
sa.--explain
option (section 16), which is off unless you choose it.ASE_CONN
environment variable, not in scripts or command lines.ase-health queries output so their security team
can review exactly what runs. I am not a lawyer; have the agreement
reviewed by one.Off by default. report --explain sends each finding to a
language model API for a three-sentence plain-English explanation.
Object names are replaced with placeholders (OBJ_1…) first,
but the finding text still goes to an external provider, so only use it
where the client’s policy allows. You need
pip install -e ".[ai]", an API key in the provider’s
environment variable, and ASE_HEALTH_MODEL set to a current
model name. The rules engine never depends on it, and nothing in this
manual’s workflow requires it. This path is untested against the live
API.
| Command | Purpose |
|---|---|
scan --label NAME [--out file.json] [--db file] |
collect from a live server into history |
ping |
test connection and all queries; stores nothing |
report --server NAME (or
--snapshot FILE) |
render a report. Options: --format (md, html, json,
csv, summary, summary-html), --out FILE,
--config FILE, --fail-on (HIGH or CRITICAL),
--explain, --db FILE |
export [--out file.csv] [--config FILE] |
latest findings of all servers, one CSV |
history |
list servers and snapshot counts |
prune --days N |
delete older snapshots |
load FILES... |
import JSON snapshots |
config [--out file.toml] |
print or write the settings template |
rules |
list rule IDs |
licence request / licence install FILE /
licence status |
get, install and check a licence (license also works);
the only commands that run without one |
queries |
print every SQL statement the tool can run |
Environment variables: ASE_CONN
(connection string); ASE_HEALTH_MODEL (only for
--explain). Exit codes: 0 success; 1 an
error, or --fail-on matched, or ping found
warnings; 3 no valid licence.
The rule: every command except
ase-health licence ... quits with exit code 3 unless a
valid, unexpired licence file is installed at
.ase-health/licence.json in your home folder (Windows:
C:\\Users\\you\\.ase-health). If the folder or the file is
missing, altered, expired, for another product, or issued for a
different installation, the tool quits and tells you why.
Getting a licence (manual, by email):
ase-health licence request. It
creates the .ase-health folder and prints a short text
containing your Installation ID.ase-health licence install licence-1234567890.json
ase-health licence status
Renewal works the same way: install the newer file over the old one.
While licensed: a reminder appears on the error stream (it does not disturb CSV or JSON output) during the last 14 days.
Commands that work without a licence:
licence request, licence status,
licence install, and --help.
Offline: licence files are verified with a public key built into the tool. No internet or licence server is needed.
Important: do not delete the
.ase-health folder; the tool will quit until you install
the licence again. Keep a copy of your licence file. If a licence is
bound to your Installation ID and you lose the folder, a new request is
needed (the ID changes).
Limits to know about: this is a light, manual scheme for the testing stage. Setting the system clock back does not revive an expired licence, but anyone who edits the source code can remove the check. A licence file that is not bound to an Installation ID can be copied to another machine.
Environment variable: ASE_HEALTH_HOME
moves the folder elsewhere (it must still hold
licence.json).
Developer builds: if no public key has been built in
(see owner-tools/README.md), the tool runs with a
“DEVELOPER BUILD: licence not enforced” warning and licence files cannot
be installed.
Also printed by ase-health queries. Statements
containing {db} are run once per user database after the
name is validated.
-- version
select @@version;-- server_time
select getdate();-- databases
select name, status, status2, dumptrdate from master..sysdatabases;-- config
select c.name, cu.value from master..sysconfigures c, master..syscurconfigs cu where c.config = cu.config;-- db_sizes
select db_name(dbid), sum(size) * @@maxpagesize / 1048576.0 from master..sysusages group by dbid;-- sa_role_holders
select l.name from master..syslogins l, master..sysloginroles r, master..syssrvroles s where l.suid = r.suid and r.srid = s.srid and s.name = 'sa_role';-- log_usage
select db_name(dbid), sum(size), lct_admin('logsegment_freepages', dbid) from master..sysusages where segmap & 4 = 4 group by dbid;-- open_transactions
select db_name(dbid), spid, starttime from master..syslogshold where name <> '$replication_truncation_point';-- connections
select count(*) from master..sysprocesses where suid > 0;-- table_stats
select o.name, t.rowcnt, t.moddate from {db}..systabstats t, {db}..sysobjects o where t.id = o.id and t.indid in (0, 1) and o.type = 'U';-- orphan_users
select u.name, case when exists (select 1 from {db}..sysprotects p where p.uid = u.uid) then 1 else 0 end from {db}..sysusers u where u.suid > 0 and u.suid not in (select suid from master..syslogins);ase-health/
pyproject.toml package definition
README.md short quick start
docs/MANUAL.* this manual
src/ase_health/
cli.py commands
collectors.py the SELECTs and snapshot builder
connector.py ODBC connection
config.py thresholds and validation
store.py SQLite history
rules/core.py the rules (your expertise goes here)
summary.py management summary
export.py CSV export
report.py technical report
explain.py optional AI layer
licensing.py, ed25519.py trial clock and signed licence verification
tests/ 60 automated tests
samples/ demo snapshot, demo history builder, config template
Copy this table into a spreadsheet and fill it in as you go.
| # | Test | Command or action | Expected | Actual | Pass / Fail | Notes |
|---|---|---|---|---|---|---|
| 1 | Install | pip install -e . |
no errors | |||
| 2 | Unit tests | python -m unittest discover tests |
60 OK | |||
| 3 | Demo report | section 4.2 | RED status, 14 findings | |||
| 4 | Config typo | section 4.4 | clear error | |||
| 5 | ODBC driver listed | odbcinst -q -d / Drivers tab |
driver visible | |||
| 6 | Connection | ase-health ping |
connected | |||
| 7 | Every query runs | ping |
no warnings | |||
| 8 | Scan stores | scan, then history |
1 snapshot | |||
| 9 to 20 | One row per rule in section 13 | tool matches ASE | ||||
| 21 | Summary page | --format summary-html |
readable, correct | |||
| 22 | CSV opens in Excel | columns correct | ||||
| 23 | Second scan next day | scan again |
2 snapshots, “since previous” line | |||
| 24 | Permission list | minimum grants written down | ||||
| 25 | Quits without licence | any command on a customer build | message and exit code 3 | |||
| 26 | Request text | ase-health licence request |
Installation ID shown | |||
| 27 | Install licence | ase-health licence install FILE, then
licence status |
LICENSED | |||
| 28 | Delete folder | remove .ase-health, run any command |
quits again |