Security Transparency

# Every Command We Run.
Nothing Hidden.

TuneVault's proxy executes only pre-approved commands on your Oracle server. Here's the complete list. If it's not on this page, we can't run it.

⬇ Download Lockdown Script ⬇ Plaintext Reference ⬇ Audit Verify Script
Read-only — zero writes to your database
No inbound firewall rules needed
No plaintext credentials stored — AES-256 encrypted at rest
Every action logged and auditable
Architecture

## How the Proxy Connects

The proxy runs on your server and talks outbound only. Your Oracle instance never touches the internet.

☁️
TuneVault Cloud
tunevault.app:443
HTTPS outbound
port 443 only
🖥️
Proxy Agent
your server · 127.0.0.1:3100
SQL over TCP
localhost:1521
🗄️
Oracle Database
localhost · never internet-exposed
🔒
No inbound rules
The proxy makes outbound HTTPS calls. Your firewall needs zero inbound rules from TuneVault.
🌐
Oracle stays offline
Oracle only talks to `localhost:3100`. The database port 1521 is never exposed to the internet.
📡
2 endpoints, that's it
Proxy contacts only `tunevault.app:443` — to deliver results and check for updates. No third parties.
🔑
Local API key
A 64-hex API key is generated on your server at install time. TuneVault never holds Oracle credentials.
✅ TuneVault requires
▸ Outbound HTTPS (443) from your server
▸ Oracle service account with SELECT_CATALOG_ROLE
▸ Proxy binary running on the Oracle host
❌ TuneVault does NOT need
▸ Inbound SSH (22) to your server
▸ Inbound DB port (1521) open to internet
▸ SNMP (161) or WMI access
▸ Root or SYSDBA privileges
▸ VPN or tunneling software
00

## Required Oracle Grants

Grant these privileges to the TuneVault service account before running health checks.

### 🔒 Minimum required grants

Run as SYS or SYSTEM. Replace `tunevault_user` with your service account name.

    -- Core catalog access (covers DBA_* views, V$* views)
    GRANT SELECT_CATALOG_ROLE TO tunevault_user;
    GRANT CREATE SESSION TO tunevault_user;

    -- Alert log access (not covered by SELECT_CATALOG_ROLE)
    GRANT SELECT ON V_$DIAG_ALERT_EXT TO tunevault_user;

No write access needed. TuneVault never executes INSERT, UPDATE, DELETE, or DDL statements. All queries are SELECT-only against system catalog views (DBA_*, V$*, GV$*).
AWR / ADDM checks (optional on-demand panel) require Oracle Enterprise Edition with Diagnostics Pack (`control_management_pack_access = DIAGNOSTIC+TUNING`). TuneVault checks for this license and skips these queries gracefully on Standard Edition.
01

## SQL Queries Executed Against Your Database

All queries are read-only SELECTs run during a health check. Click any row to see the literal SQL.

Instance & Version
Instance information
Identifies Oracle version, host, uptime, CPU count, SGA/PGA targets, and block size
V$DATABASEV$INSTANCEV$PARAMETER
▼

    SELECT
      d.NAME, i.INSTANCE_NAME, i.HOST_NAME, i.VERSION,
      d.PLATFORM_NAME,
      TO_CHAR(i.STARTUP_TIME, 'YYYY-MM-DD HH24:MI:SS'),
      ROUND(SYSDATE - i.STARTUP_TIME),
      (SELECT VALUE FROM v$parameter WHERE name = 'cpu_count'),
      ROUND((SELECT TO_NUMBER(VALUE)/1024/1024/1024 FROM v$parameter WHERE name = 'sga_target'), 1),
      ROUND((SELECT TO_NUMBER(VALUE)/1024/1024/1024 FROM v$parameter WHERE name = 'pga_aggregate_target'), 1),
      (SELECT TO_NUMBER(VALUE) FROM v$parameter WHERE name = 'db_block_size')
    FROM v$database d, v$instance i

Database version banner
Detects Enterprise vs Standard Edition — gates AWR/ADDM queries
V$VERSION
▼

    SELECT BANNER FROM V$VERSION WHERE ROWNUM = 1

Storage
Tablespace usage
Used/total GB and % utilisation per tablespace; flags >80% warning, >90% critical
DBA_TABLESPACE_USAGE_METRICSDBA_TABLESPACESDBA_DATA_FILES
▼

    SELECT
      ts.TABLESPACE_NAME,
      ROUND(um.USED_SPACE * ts.BLOCK_SIZE / 1024/1024/1024, 1) AS used_gb,
      ROUND(um.TABLESPACE_SIZE * ts.BLOCK_SIZE / 1024/1024/1024, 1) AS total_gb,
      ROUND(um.USED_PERCENT, 1) AS pct_used,
      CASE WHEN df.autoext > 0 THEN 1 ELSE 0 END AS autoextend
    FROM DBA_TABLESPACE_USAGE_METRICS um
    JOIN DBA_TABLESPACES ts ON ts.TABLESPACE_NAME = um.TABLESPACE_NAME
    LEFT JOIN (
      SELECT TABLESPACE_NAME,
        SUM(CASE WHEN AUTOEXTENSIBLE = 'YES' THEN 1 ELSE 0 END) AS autoext
      FROM DBA_DATA_FILES GROUP BY TABLESPACE_NAME
    ) df ON df.TABLESPACE_NAME = um.TABLESPACE_NAME
    ORDER BY um.USED_PERCENT DESC

Undo tablespace health
Undo retention, block counts, concurrency
V$UNDOSTATDBA_DATA_FILESDBA_TABLESPACES
▼

    SELECT UNDOBLKS, TXNCOUNT, MAXQUERYLEN, MAXCONCURRENCY,
           TUNED_UNDORETENTION, EXPIREDBLKS, UNEXPIREDBLKS, ACTIVEBLKS
    FROM V$UNDOSTAT WHERE ROWNUM = 1 ORDER BY END_TIME DESC

    -- Undo tablespace size
    SELECT d.TABLESPACE_NAME, SUM(d.BYTES)/1073741824,
           SUM(d.BYTES - NVL(f.FREE_BYTES,0))/1073741824,
           ROUND(SUM(d.BYTES - NVL(f.FREE_BYTES,0))/SUM(d.BYTES)*100,1), t.RETENTION
    FROM DBA_DATA_FILES d JOIN DBA_TABLESPACES t ON t.TABLESPACE_NAME=d.TABLESPACE_NAME
    LEFT JOIN (SELECT FILE_ID, SUM(BYTES) AS FREE_BYTES FROM DBA_FREE_SPACE GROUP BY FILE_ID) f
      ON f.FILE_ID=d.FILE_ID
    WHERE t.CONTENTS='UNDO' GROUP BY d.TABLESPACE_NAME, t.RETENTION

Temp tablespace usage
Temp space used/free; top sessions by temp usage to identify runaway sorts
DBA_TEMP_FREE_SPACEV$TEMPSEG_USAGE
▼

    SELECT TABLESPACE_NAME, ROUND(TABLESPACE_SIZE/1073741824,2),
           ROUND(FREE_SPACE/1073741824,2),
           ROUND((TABLESPACE_SIZE-FREE_SPACE)/NULLIF(TABLESPACE_SIZE,0)*100,1)
    FROM DBA_TEMP_FREE_SPACE

    -- Top temp-consuming sessions
    SELECT s.SID, s.SERIAL#, s.USERNAME,
           ROUND(s.BLOCKS*8192/1048576,1), s.TABLESPACE
    FROM V$TEMPSEG_USAGE s ORDER BY s.BLOCKS DESC FETCH FIRST 10 ROWS ONLY

Top segments by size
10 largest tables/indexes by GB to spot unexpected growth
DBA_SEGMENTS
▼

    SELECT OWNER, SEGMENT_NAME, SEGMENT_TYPE,
           ROUND(SUM(BYTES)/1073741824, 2) AS size_gb
    FROM DBA_SEGMENTS
    WHERE OWNER NOT IN ('SYS','SYSTEM','DBSNMP','SYSMAN','OUTLN','MDSYS',
      'ORDSYS','XDB','CTXSYS','WMSYS','EXFSYS')
    GROUP BY OWNER, SEGMENT_NAME, SEGMENT_TYPE
    ORDER BY size_gb DESC FETCH FIRST 10 ROWS ONLY

Datafile status & recycle bin
Offline/problem datafiles; wasted space from dropped-but-not-purged objects
DBA_DATA_FILESDBA_RECYCLEBIN
▼

    SELECT COUNT(*) AS problem_count,
           COUNT(CASE WHEN STATUS = 'OFFLINE' THEN 1 END) AS offline_count
    FROM DBA_DATA_FILES WHERE STATUS NOT IN ('AVAILABLE','ONLINE')

    SELECT COUNT(*) AS object_count,
           ROUND(SUM(SPACE)*8192/1073741824, 2) AS size_gb
    FROM DBA_RECYCLEBIN

Memory (SGA / PGA)
SGA components & hit ratios
Buffer cache, library cache, dictionary cache hit ratios; shared pool free %
V$SGAV$SYSSTATV$LIBRARYCACHEV$ROWCACHEV$SGASTAT
▼

    SELECT ROUND(SUM(VALUE)/1024/1024/1024, 1) FROM V$SGA

    -- Buffer cache hit ratio
    SELECT ROUND((1 - (phys.VALUE / (db_gets.VALUE + con_gets.VALUE))) * 100, 1)
    FROM (SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'physical reads') phys,
         (SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'db block gets') db_gets,
         (SELECT VALUE FROM V$SYSSTAT WHERE NAME = 'consistent gets') con_gets

    -- Library cache hit ratio
    SELECT ROUND(SUM(PINS - RELOADS) / NULLIF(SUM(PINS), 0) * 100, 1) FROM V$LIBRARYCACHE

    -- Dictionary cache hit ratio
    SELECT ROUND(SUM(GETS - GETMISSES) / NULLIF(SUM(GETS), 0) * 100, 1) FROM V$ROWCACHE

    -- Shared pool free %
    SELECT ROUND(free_bytes.val / total_bytes.val * 100, 1)
    FROM (SELECT SUM(BYTES) AS val FROM V$SGASTAT WHERE POOL='shared pool' AND NAME='free memory') free_bytes,
         (SELECT SUM(BYTES) AS val FROM V$SGASTAT WHERE POOL='shared pool') total_bytes

PGA statistics
PGA target vs allocated, over-allocation count, cache hit %, work area execution modes
V$PGASTATV$PARAMETERV$SQL_WORKAREA_HISTOGRAM
▼

    SELECT
      ROUND((SELECT TO_NUMBER(VALUE)/1024/1024/1024 FROM v$parameter WHERE name='pga_aggregate_target'),1),
      ROUND((SELECT VALUE/1024/1024/1024 FROM V$PGASTAT WHERE NAME='total PGA allocated'),1),
      ROUND((SELECT VALUE/1024/1024/1024 FROM V$PGASTAT WHERE NAME='maximum PGA allocated'),1),
      (SELECT VALUE FROM V$PGASTAT WHERE NAME='over allocation count'),
      ROUND((SELECT VALUE FROM V$PGASTAT WHERE NAME='cache hit percentage'),1)
    FROM DUAL

OS memory & CPU stats (via Oracle)
Physical memory, free memory, CPU count, CPU utilisation, I/O wait — no shell access required
V$OSSTAT
▼

    SELECT STAT_NAME, VALUE FROM V$OSSTAT
    WHERE STAT_NAME IN (
      'NUM_CPUS','IDLE_TIME','BUSY_TIME','USER_TIME',
      'SYS_TIME','IOWAIT_TIME',
      'PHYSICAL_MEMORY_BYTES','FREE_MEMORY_BYTES'
    )

Performance
Top 10 SQL by elapsed time
Most resource-intensive SQL statements; excludes system schemas and internal metadata
V$SQL
▼

    SELECT SQL_ID, SUBSTR(SQL_TEXT, 1, 500), EXECUTIONS,
      ROUND(ELAPSED_TIME/1000000, 1), ROUND(CPU_TIME/1000000, 1),
      BUFFER_GETS, DISK_READS, ROWS_PROCESSED,
      CASE WHEN EXECUTIONS > 0 THEN ROUND(ELAPSED_TIME/EXECUTIONS/1000, 2) ELSE 0 END,
      CASE WHEN EXECUTIONS > 0 THEN ROUND(BUFFER_GETS/EXECUTIONS) ELSE 0 END,
      PLAN_HASH_VALUE
    FROM V$SQL
    WHERE EXECUTIONS > 0 AND ELAPSED_TIME > 0
      AND PARSING_SCHEMA_NAME NOT IN ('SYS','SYSTEM','DBSNMP','SYSMAN','OUTLN',
        'MDSYS','ORDSYS','EXFSYS','WMSYS','APPQOSSYS','DBSFWUSER')
      AND SQL_TEXT NOT LIKE '%v$%' AND SQL_TEXT NOT LIKE '%V$%'
      AND COMMAND_TYPE IN (2, 3, 6, 7, 189)
    ORDER BY ELAPSED_TIME DESC FETCH FIRST 10 ROWS ONLY

Top 15 wait events
Leading wait events (excluding idle) consuming database time
V$SYSTEM_EVENT
▼

    SELECT EVENT, WAIT_CLASS, TOTAL_WAITS,
      ROUND(TIME_WAITED/100, 1) AS time_waited_s,
      CASE WHEN TOTAL_WAITS > 0
        THEN ROUND((TIME_WAITED/100/TOTAL_WAITS)*1000, 2) ELSE 0 END AS avg_wait_ms
    FROM V$SYSTEM_EVENT
    WHERE WAIT_CLASS NOT IN ('Idle') AND TOTAL_WAITS > 0
    ORDER BY TIME_WAITED DESC FETCH FIRST 15 ROWS ONLY

Index health (top 20 fragmented)
Indexes with high B-tree depth (>3) or low direct access % — rebuild candidates
DBA_INDEXESDBA_IND_STATISTICSV$PARAMETER
▼

    SELECT i.OWNER, i.INDEX_NAME, i.TABLE_NAME,
      ROUND(s.LEAF_BLOCKS *
        (SELECT TO_NUMBER(VALUE) FROM v$parameter WHERE name='db_block_size')
        / 1024/1024) AS size_mb,
      i.BLEVEL, s.LEAF_BLOCKS, i.CLUSTERING_FACTOR,
      NVL(s.PCT_DIRECT_ACCESS,100), i.STATUS,
      CASE
        WHEN i.STATUS != 'VALID' THEN 'unusable'
        WHEN i.BLEVEL > 4 THEN 'critical'
        WHEN NVL(s.PCT_DIRECT_ACCESS,100) < 50 THEN 'critical'
        WHEN i.BLEVEL > 3 THEN 'fragmented'
        WHEN NVL(s.PCT_DIRECT_ACCESS,100) < 70 THEN 'fragmented'
        ELSE 'ok'
      END AS health_status
    FROM DBA_INDEXES i
    LEFT JOIN DBA_IND_STATISTICS s
      ON s.OWNER=i.OWNER AND s.INDEX_NAME=i.INDEX_NAME AND s.PARTITION_NAME IS NULL
    WHERE i.OWNER NOT IN ('SYS','SYSTEM','DBSNMP','SYSMAN','OUTLN','MDSYS','ORDSYS',
      'EXFSYS','WMSYS','XDB','CTXSYS','APPQOSSYS','DBSFWUSER',
      'APEX_040000','APEX_040200','APEX_050000','FLOWS_FILES')
      AND i.INDEX_TYPE = 'NORMAL' AND NVL(s.LEAF_BLOCKS, 0) > 100
    ORDER BY CASE WHEN i.STATUS != 'VALID' THEN 1 WHEN i.BLEVEL > 4 THEN 2
                  WHEN i.BLEVEL > 3 THEN 3 ELSE 4 END,
             s.LEAF_BLOCKS DESC NULLS LAST
    FETCH FIRST 20 ROWS ONLY

Resource limits & sessions
Session/process counts, blocked sessions, long-running SQL, resource utilisation vs. configured limits
V$RESOURCE_LIMITV$SESSION
▼

    -- Resource limits
    SELECT RESOURCE_NAME, CURRENT_UTILIZATION, MAX_UTILIZATION, INITIAL_ALLOCATION, LIMIT_VALUE
    FROM V$RESOURCE_LIMIT
    WHERE RESOURCE_NAME IN (
      'sessions','processes','enqueue_locks','enqueue_resources',
      'dml_locks','temporary_table_locks','transactions','max_rollback_segments'
    )

    -- Session counts
    SELECT COUNT(*), COUNT(CASE WHEN STATUS='ACTIVE' AND TYPE='USER' THEN 1 END),
           COUNT(CASE WHEN TYPE='USER' THEN 1 END) FROM V$SESSION

    -- Blocked sessions
    SELECT COUNT(*) FROM V$SESSION WHERE BLOCKING_SESSION IS NOT NULL AND STATUS='ACTIVE'

    -- Long-running SQL
    SELECT COUNT(*), ROUND(MAX((SYSDATE - SQL_EXEC_START)*1440), 1)
    FROM V$SESSION WHERE STATUS='ACTIVE' AND TYPE='USER'
      AND SQL_EXEC_START IS NOT NULL AND (SYSDATE - SQL_EXEC_START)*1440 > 5

Disk sort & full table scan ratios
Disk vs in-memory sort ratio; full table scan vs index lookup ratio
V$SYSSTAT
▼

    SELECT d.VALUE AS disk_sorts, m.VALUE AS mem_sorts
    FROM (SELECT VALUE FROM V$SYSSTAT WHERE NAME='sorts (disk)') d,
         (SELECT VALUE FROM V$SYSSTAT WHERE NAME='sorts (memory)') m

    SELECT s.VALUE AS long_scans, i.VALUE AS index_lookups
    FROM (SELECT VALUE FROM V$SYSSTAT WHERE NAME='table scans (long tables)') s,
         (SELECT VALUE FROM V$SYSSTAT WHERE NAME='table fetch by rowid') i

Invalid objects, stale statistics, SCN headroom
Invalid PL/SQL objects, stale optimizer stats, and days until SCN exhaustion
DBA_OBJECTSDBA_TAB_STATISTICSV$DATABASE
▼

    SELECT COUNT(*),
      COUNT(CASE WHEN OBJECT_TYPE IN ('PACKAGE BODY','PACKAGE') THEN 1 END),
      COUNT(CASE WHEN OBJECT_TYPE='PROCEDURE' THEN 1 END),
      COUNT(CASE WHEN OBJECT_TYPE='VIEW' THEN 1 END),
      COUNT(CASE WHEN OBJECT_TYPE='TRIGGER' THEN 1 END)
    FROM DBA_OBJECTS WHERE STATUS='INVALID'
      AND OWNER NOT IN ('SYS','SYSTEM','DBSNMP','SYSMAN','OUTLN','MDSYS','ORDSYS',
        'XDB','CTXSYS','WMSYS','EXFSYS','APPQOSSYS','DBSFWUSER','OJVMSYS','DVSYS','LBACSYS')

    SELECT COUNT(*), COUNT(CASE WHEN LAST_ANALYZED IS NULL THEN 1 END)
    FROM DBA_TAB_STATISTICS WHERE STALE_STATS='YES'
      AND OWNER NOT IN ('SYS','SYSTEM','DBSNMP','SYSMAN','OUTLN','MDSYS','ORDSYS','XDB','CTXSYS','WMSYS','EXFSYS')

    -- SCN headroom
    SELECT CURRENT_SCN,
      ROUND((TO_NUMBER(SYSDATE-TO_DATE('01-01-1988','DD-MM-YYYY'))*24*3600*16384*1024-CURRENT_SCN)/(24*3600*16384),0)
    FROM V$DATABASE

Alert log errors (last 24h)
ORA- errors, checkpoints, corruption warnings, TNS errors from the in-memory alert log view
V$DIAG_ALERT_EXT
▼

    SELECT TO_CHAR(ORIGINATING_TIMESTAMP,'YYYY-MM-DD HH24:MI:SS'), MESSAGE_TEXT
    FROM V$DIAG_ALERT_EXT
    WHERE ORIGINATING_TIMESTAMP > SYSDATE-1
      AND (MESSAGE_TEXT LIKE 'ORA-%' OR MESSAGE_TEXT LIKE '%checkpoint%'
           OR MESSAGE_TEXT LIKE '%corruption%' OR MESSAGE_TEXT LIKE '%recovery%'
           OR MESSAGE_TEXT LIKE '%error%' OR MESSAGE_TEXT LIKE '%warning%'
           OR MESSAGE_TEXT LIKE '%TNS-%' OR MESSAGE_TEXT LIKE '%instance%'
           OR MESSAGE_TEXT LIKE 'Thread%')
    ORDER BY ORIGINATING_TIMESTAMP DESC FETCH FIRST 200 ROWS ONLY
    -- Note: requires GRANT SELECT ON V_$DIAG_ALERT_EXT (not in SELECT_CATALOG_ROLE)

Backup & Recovery
RMAN backup freshness
Last full/incremental/archivelog backup time and size; flags >48h since last full as critical
V$RMAN_BACKUP_JOB_DETAILS
▼

    SELECT INPUT_TYPE, STATUS,
      TO_CHAR(START_TIME,'YYYY-MM-DD HH24:MI:SS'),
      TO_CHAR(END_TIME,'YYYY-MM-DD HH24:MI:SS'),
      ROUND((SYSDATE - END_TIME)*24, 1) AS hours_ago,
      ROUND(OUTPUT_BYTES/1073741824, 2) AS size_gb, ELAPSED_SECONDS
    FROM (
      SELECT INPUT_TYPE, STATUS, START_TIME, END_TIME, OUTPUT_BYTES, ELAPSED_SECONDS,
             ROW_NUMBER() OVER (PARTITION BY INPUT_TYPE ORDER BY END_TIME DESC) AS RN
      FROM V$RMAN_BACKUP_JOB_DETAILS WHERE STATUS='COMPLETED'
    ) WHERE RN=1

Fast Recovery Area (FRA) usage
FRA size, used/reclaimable space, and breakdown by file type
V$RECOVERY_FILE_DESTV$FLASH_RECOVERY_AREA_USAGEV$ARCHIVED_LOG
▼

    SELECT NAME, ROUND(SPACE_LIMIT/1073741824,2), ROUND(SPACE_USED/1073741824,2),
      ROUND(SPACE_RECLAIMABLE/1073741824,2), NUMBER_OF_FILES
    FROM V$RECOVERY_FILE_DEST

    SELECT FILE_TYPE, ROUND(PERCENT_SPACE_USED,1),
           ROUND(PERCENT_SPACE_RECLAIMABLE,1), NUMBER_OF_FILES
    FROM V$FLASH_RECOVERY_AREA_USAGE ORDER BY PERCENT_SPACE_USED DESC

    SELECT ROUND(SUM(BLOCKS * BLOCK_SIZE)/1073741824, 2)
    FROM V$ARCHIVED_LOG WHERE COMPLETION_TIME > SYSDATE-1 AND STANDBY_DEST='NO'

Archivelog mode & log switch rate
Confirms ARCHIVELOG mode; measures log switch frequency (alert if >20/hour)
V$DATABASEV$INSTANCEV$ARCHIVED_LOGV$LOG_HISTORY
▼

    SELECT LOG_MODE, ROUND((SYSDATE - STARTUP_TIME)*24) FROM V$DATABASE, V$INSTANCE

    SELECT TO_CHAR(COMPLETION_TIME,'YYYY-MM-DD HH24'), COUNT(*),
           ROUND(SUM(BLOCKS*BLOCK_SIZE)/1048576, 1)
    FROM V$ARCHIVED_LOG WHERE COMPLETION_TIME > SYSDATE-1 AND STANDBY_DEST='NO'
    GROUP BY TO_CHAR(COMPLETION_TIME,'YYYY-MM-DD HH24') ORDER BY 1 DESC

    SELECT ROUND(COUNT(*)/24.0, 1), COUNT(*) FROM V$LOG_HISTORY WHERE FIRST_TIME > SYSDATE-1

Backup corruption check
Corruption markers in RMAN backup sets and image copies
V$BACKUP_CORRUPTIONV$COPY_CORRUPTION
▼

    SELECT COUNT(*), SUM(BLOCKS) FROM V$BACKUP_CORRUPTION
    SELECT COUNT(*), SUM(BLOCKS) FROM V$COPY_CORRUPTION

Security
Default-password accounts
OPEN accounts using well-known default passwords (Oracle's advisory view)
DBA_USERS_WITH_DEFPWD
▼

    SELECT COUNT(*) FROM DBA_USERS_WITH_DEFPWD WHERE ACCOUNT_STATUS = 'OPEN'

Dangerous PUBLIC grants & DBA users
PUBLIC privilege escalation risk; non-system accounts with DBA privilege
DBA_SYS_PRIVS
▼

    -- Dangerous PUBLIC grants
    SELECT COUNT(*) FROM DBA_SYS_PRIVS WHERE GRANTEE = 'PUBLIC'
      AND PRIVILEGE IN ('CREATE PROCEDURE','CREATE ANY PROCEDURE',
        'CREATE ANY TRIGGER','ALTER SYSTEM','ALTER DATABASE',
        'DROP ANY TABLE','EXECUTE ANY PROCEDURE')

    -- DBA-privileged user count
    SELECT COUNT(DISTINCT GRANTEE) FROM DBA_SYS_PRIVS
    WHERE PRIVILEGE='DBA' AND GRANTEE NOT IN ('SYS','SYSTEM','DBA','SYSMAN')

Password policy & audit settings
Password complexity function and audit trail configuration
DBA_PROFILESV$PARAMETERDBA_USERS
▼

    SELECT LIMIT FROM DBA_PROFILES WHERE PROFILE='DEFAULT' AND RESOURCE_NAME='PASSWORD_VERIFY_FUNCTION'
    SELECT VALUE FROM V$PARAMETER WHERE NAME='audit_trail'

    -- Schema-only (no-auth) open accounts
    SELECT COUNT(*) FROM DBA_USERS
    WHERE ACCOUNT_STATUS='OPEN' AND AUTHENTICATION_TYPE='NONE'
      AND USERNAME NOT IN ('SYS','SYSTEM')

Oracle Applications (EBS) — executes only when EBS detected
Conditional. TuneVault probes `APPS.DUAL` at connection time to detect EBS. These queries only run if the probe succeeds. On non-EBS Oracle databases, this entire section is skipped. The EBS detection result is passed to the AI Summary only.
EBS detection probe
Single-row probe to check if APPS schema exists; gates all EBS-specific checks
APPS.DUALEBS only
▼

    SELECT 1 FROM APPS.DUAL WHERE ROWNUM = 1
    -- If this query fails (ORA-00942), EBS is not present. All APPS.* queries are skipped.

Concurrent Manager health
Running vs max processes for each Concurrent Manager queue
APPS.FND_CONCURRENT_QUEUESAPPS.FND_CONCURRENT_QUEUES_VLEBS only
▼

    SELECT b.user_concurrent_queue_name, b.node_name,
           a.running_processes, a.max_processes
    FROM apps.fnd_concurrent_queues a, apps.fnd_concurrent_queues_vl b
    WHERE a.concurrent_queue_id = b.concurrent_queue_id

Pending request count & WF components
Queued/running concurrent requests; Workflow service component statuses
APPS.FND_CONCURRENT_REQUESTSAPPS.FND_SVC_COMPONENTSEBS only
▼

    SELECT phase_code, COUNT(*) FROM APPS.FND_CONCURRENT_REQUESTS
    WHERE phase_code IN ('P','R') GROUP BY phase_code

    SELECT component_type, component_name, component_status, startup_mode
    FROM apps.fnd_svc_components WHERE component_type LIKE 'WF%' ORDER BY 1, 2

Workflow notification & error queues
Stuck notifications (open >1 hour); WF error queue depth
APPS.WF_NOTIFICATIONSAPPS.WF_ERROREBS only
▼

    SELECT COUNT(*) FROM APPS.WF_NOTIFICATIONS
    WHERE STATUS='OPEN' AND MAIL_STATUS='MAIL' AND BEGIN_DATE < SYSDATE - 1/24

    SELECT COUNT(*) FROM APPS.WF_ERROR

ADDM (on-demand panel — Enterprise Edition + Diagnostics Pack only)
License gate. TuneVault checks `V$VERSION` for 'ENTERPRISE' and `DBA_FEATURE_USAGE_STATISTICS` for Diagnostics Pack before running any AWR/ADDM queries. Skipped silently on Standard Edition.
ADDM findings (AWR-backed)
Automatic Database Diagnostic Monitor findings for a configurable lookback window
DBA_HIST_SNAPSHOTDBA_HIST_ADDM_TASKSDBA_ADVISOR_FINDINGSDBA_ADVISOR_RECOMMENDATIONS
▼

    SELECT MIN(SNAP_ID), MAX(SNAP_ID), MIN(BEGIN_INTERVAL_TIME), MAX(END_INTERVAL_TIME)
    FROM DBA_HIST_SNAPSHOT WHERE END_INTERVAL_TIME > SYSDATE - :lookback_hours/24

    SELECT TASK_ID, TASK_NAME FROM DBA_HIST_ADDM_TASKS
    WHERE BEGIN_SNAP_ID = :begin_snap AND END_SNAP_ID = :end_snap
      AND STATUS = 'COMPLETED' FETCH FIRST 1 ROWS ONLY

    SELECT f.FINDING_ID, f.TYPE, f.MESSAGE, f.BENEFIT,
           d.ATTR1 AS recommendation, d.TYPE AS rec_type
    FROM DBA_ADVISOR_FINDINGS f
    LEFT JOIN DBA_ADVISOR_RECOMMENDATIONS d ON d.TASK_ID=f.TASK_ID AND d.FINDING_ID=f.FINDING_ID
    WHERE f.TASK_ID = :task_id ORDER BY f.BENEFIT DESC NULLS LAST FETCH FIRST 20 ROWS ONLY

02

## Shell Commands

The complete whitelist of OS commands the proxy may execute on your server. All are read-only status checks. No commands modify files, change configuration, or write to disk.

Core health checks use zero shell commands. CPU, memory, and I/O wait metrics are read from `V$OSSTAT` via Oracle SQL. Shell commands only run on EBS 12.2.x environments to check application-tier service status — and only the exact commands below are permitted.
Core Health Checks (200+ checks)

Command | Purpose | Condition | Writes?
--- | --- | --- | ---
`— none —` | All core OS metrics (CPU, memory, I/O wait) are read via `V$OSSTAT` through the Oracle connection. No shell commands required for any of the 200+ core health checks. | always | NO

EBS 12.2.x Application-Tier Commands — conditional (complete whitelist)

All commands use `$ADMIN_SCRIPTS_HOME` — no hardcoded paths. Only `status` subcommands are whitelisted. `admanagedsrvctl.sh` is the unified controller for all managed servers in EBS 12.2.x.

Command | Purpose | Condition | Writes?
--- | --- | --- | ---
`adcmctl.sh status` | Concurrent Manager status. Reports running/max processes per queue. | EBS detected | NO
`adalnctl.sh status` | APPS TNS Listener status. Checks if the application-tier listener is running. | EBS detected | NO
`admanagedsrvctl.sh status oacore_server1` | OACore managed server status. Hosts Oracle Applications Framework pages. | EBS detected | NO
`admanagedsrvctl.sh status forms_server1` | Forms managed server status. Required for EBS forms-based modules. | EBS detected | NO
`admanagedsrvctl.sh status oafm_server1` | OA Framework managed server status. Hosts OAF-based Oracle Applications pages. | EBS detected | NO
`admanagedsrvctl.sh status wfmlrsvc` | Workflow Mailer managed service status. Reports if outbound workflow notifications are processing. | EBS detected | NO
`admanagedsrvctl.sh status opp` | Output Post Processor status. Handles PDF/EXCEL output for concurrent requests. | EBS detected | NO
`adadminsrvctl.sh status` | Admin Server status. The WLS administration server managing all managed servers. | EBS detected | NO
`adnodemgrctl.sh status` | Node Manager status. Controls WebLogic managed server lifecycle on this node. | EBS detected | NO
`adopmnctl.sh status` | OPMN status. Oracle Process Manager and Notification Server for OHS/Apache. | EBS detected | NO
`mwactl.sh status` | Middleware Agent status. Monitors and reports on WLS middleware component health. | EBS detected | NO
`adapcctl.sh status` | Apache/OHS status. Reports if the Oracle HTTP Server is running and accepting requests. | EBS detected | NO

Hard whitelist enforcement. The proxy validates the exact script filename and argument list against a compiled whitelist before execution. Any command not in this table — including start/stop/restart variants — is rejected with a 403. Scripts are resolved via `$ADMIN_SCRIPTS_HOME` at runtime; the path itself is never accepted from the caller. Execution is logged with timestamp, requester IP, exit code, and a SHA-256 hash of the output.
03

## What TuneVault Never Does

Explicit guarantees. These are enforced in the proxy binary — not policy statements.

✗
Never modifies your data
Zero INSERT, UPDATE, DELETE, or MERGE statements. All SQL is SELECT-only against system catalog views.
✗
Never executes DDL
No CREATE, ALTER, DROP, or TRUNCATE. Can't create objects, can't destroy them.
✗
Never runs as SYS or SYSDBA
Only the service account you create is used. SYSDBA privilege is not needed and not requested.
✗
Never changes passwords
No ALTER USER statements. No password reads beyond what Oracle reports via DBA_USERS_WITH_DEFPWD (which stores no plaintext).
✗
Never stores Oracle credentials
Credentials live only in the proxy's local environment on your server. TuneVault never transmits or stores them.
✗
Never opens inbound ports
The proxy binds to `127.0.0.1:3100` only. No external inbound ports. No VPN. No SSH tunnel.
✗
Never sends data to third parties
Metrics go only to tunevault.app. No analytics SDKs, no third-party telemetry, no external tracking.
✗
Never reads user data rows
All queries target system catalog views (DBA_*, V$*, GV$*). No SELECT against application tables.
04

## Customer Lockdown Script

Run this before installing the proxy. It creates a restricted OS user, sets filesystem permissions, and configures sudoers with a command whitelist.

🔐
tunevault-lockdown.sh
Creates a hardened environment for the TuneVault proxy on your Oracle server. Principle of least privilege throughout — the proxy user can only do exactly what's needed.

1. Creates restricted OS user `tunevault` with no login shell
2. Sets `tunevault` as owner of the proxy install directory
3. Configures sudoers with explicit command whitelist (NOPASSWD for allowed commands only)
4. Prints a verification summary — inspect before running proxy

⬇ Download lockdown.sh

Full script — read every line before running:

tunevault-lockdown.sh
⬇ Download

    #!/bin/bash
    # tunevault-lockdown.sh
    # ==================================================
    # Run this on your Oracle server BEFORE installing
    # the TuneVault proxy. It creates a restricted OS
    # user and configures minimal sudo privileges.
    #
    # Usage:
    #   chmod +x tunevault-lockdown.sh
    #   sudo ./tunevault-lockdown.sh [--install-dir /opt/tunevault]
    #
    # Requirements: bash, sudo, useradd/adduser
    # Tested on: Oracle Linux 7/8/9, RHEL 7/8/9, Ubuntu 20/22
    # ==================================================

    set -euo pipefail

    INSTALL_DIR=${1:-/opt/tunevault}
    PROXY_USER=tunevault
    PROXY_GROUP=tunevault
    LOG_FILE=/var/log/tunevault-lockdown.log

    # Must run as root
    if [ "$(id -u)" != "0" ]; then
      echo "ERROR: Must run as root (sudo ./tunevault-lockdown.sh)"
      exit 1
    fi

    echo "========================================"
    echo " TuneVault Lockdown Script"
    echo " $(date)"
    echo " Install dir: $INSTALL_DIR"
    echo "========================================"
    echo ""

    # --- Create restricted group and user ---
    if ! getent group "$PROXY_GROUP" &>/dev/null; then
      echo "[1/4] Creating group: $PROXY_GROUP"
      groupadd --system "$PROXY_GROUP"
    else
      echo "[1/4] Group $PROXY_GROUP already exists — skipping"
    fi

    if ! id "$PROXY_USER" &>/dev/null; then
      echo "[2/4] Creating user: $PROXY_USER (no login shell, system account)"
      useradd \
        --system \
        --gid "$PROXY_GROUP" \
        --shell /sbin/nologin \
        --no-create-home \
        --comment "TuneVault proxy service account" \
        "$PROXY_USER"
    else
      echo "[2/4] User $PROXY_USER already exists — skipping"
    fi

    # --- Create and lock down install directory ---
    echo "[3/4] Setting up install directory: $INSTALL_DIR"
    mkdir -p "$INSTALL_DIR"
    chown "$PROXY_USER:$PROXY_GROUP" "$INSTALL_DIR"
    chmod 750 "$INSTALL_DIR"

    # Log directory (writable by proxy user only)
    mkdir -p "$INSTALL_DIR/logs"
    chown "$PROXY_USER:$PROXY_GROUP" "$INSTALL_DIR/logs"
    chmod 700 "$INSTALL_DIR/logs"

    # --- Configure sudoers whitelist ---
    echo "[4/4] Writing sudoers whitelist..."
    SUDOERS_FILE=/etc/sudoers.d/tunevault

    # Remove existing file if present
    [ -f "$SUDOERS_FILE" ] && rm -f "$SUDOERS_FILE"

    cat > "$SUDOERS_FILE" << 'SUDOERS_EOF'
    # TuneVault proxy — minimal sudo whitelist (EBS 12.2.x application tier)
    # Generated by tunevault-lockdown.sh
    # DO NOT edit manually — re-run lockdown.sh to update
    #
    # All paths use $ADMIN_SCRIPTS_HOME set in the oracle user environment.
    # Only "status" subcommands are listed — start/stop/restart are NOT granted.

    Defaults:tunevault env_keep += "ADMIN_SCRIPTS_HOME"

    # Non-managed services
    Cmnd_Alias TUNEVAULT_NON_MANAGED = \
      $ADMIN_SCRIPTS_HOME/adcmctl.sh status, \
      $ADMIN_SCRIPTS_HOME/adalnctl.sh status, \
      $ADMIN_SCRIPTS_HOME/adadminsrvctl.sh status, \
      $ADMIN_SCRIPTS_HOME/adnodemgrctl.sh status, \
      $ADMIN_SCRIPTS_HOME/adopmnctl.sh status, \
      $ADMIN_SCRIPTS_HOME/mwactl.sh status, \
      $ADMIN_SCRIPTS_HOME/adapcctl.sh status

    # Managed servers (unified admanagedsrvctl.sh controller)
    Cmnd_Alias TUNEVAULT_MANAGED = \
      $ADMIN_SCRIPTS_HOME/admanagedsrvctl.sh status oacore_server1, \
      $ADMIN_SCRIPTS_HOME/admanagedsrvctl.sh status forms_server1, \
      $ADMIN_SCRIPTS_HOME/admanagedsrvctl.sh status oafm_server1, \
      $ADMIN_SCRIPTS_HOME/admanagedsrvctl.sh status wfmlrsvc, \
      $ADMIN_SCRIPTS_HOME/admanagedsrvctl.sh status opp

    tunevault ALL=(oracle) NOPASSWD: TUNEVAULT_NON_MANAGED, TUNEVAULT_MANAGED

    # No other commands are permitted
    SUDOERS_EOF

    # Validate sudoers file syntax
    if command -v visudo &>/dev/null; then
      if visudo -c -f "$SUDOERS_FILE" &>/dev/null; then
        echo "    sudoers syntax OK: $SUDOERS_FILE"
      else
        echo "ERROR: sudoers validation failed — removing $SUDOERS_FILE"
        rm -f "$SUDOERS_FILE"
        exit 1
      fi
    fi
    chmod 440 "$SUDOERS_FILE"

    # --- Print verification summary ---
    echo ""
    echo "========================================"
    echo " Lockdown complete. Verify before use:"
    echo "========================================"
    echo ""
    echo "OS user:"
    id tunevault 2>/dev/null || echo "  ERROR: user not found"
    echo ""
    echo "Install directory:"
    ls -la "$INSTALL_DIR" 2>/dev/null | head -5
    echo ""
    echo "Sudoers whitelist:"
    cat "$SUDOERS_FILE" 2>/dev/null
    echo ""
    echo "Shell (should be /sbin/nologin or /bin/false):"
    getent passwd tunevault | cut -d: -f7
    echo ""
    echo "========================================"
    echo " Next: install the proxy as user 'tunevault'"
    echo " See: https://tunevault.app/docs/oracle-setup"
    echo "========================================"

05

## Audit & Logging

Every action TuneVault takes on your infrastructure is recorded. Your security team can audit the complete history at any time.

📋
TuneVault Dashboard
Every health check run appears in your dashboard with timestamp, duration, score, and a complete record of which checks were executed. Filterable by date range and connection.
🖥️
Local Proxy Logs
The proxy writes structured JSON logs to `/opt/tunevault/logs/`. Each entry records: timestamp, command or query type, execution duration, success/failure, and a result hash (not the data itself).
🔎
Verification Script
Download `lockdown-verify.sh` to capture a live 30-second syscall trace of the proxy using strace or auditd. See every file open, network connection, and process execution in real time.
🔒
Immutable Log Format
Proxy logs are append-only. The log file is owned by `tunevault:tunevault` and not writable by other accounts. Hash chaining detects any post-hoc modification.
Questions from your security team? We're happy to do a live walkthrough — screen share, walk through the proxy source, answer specific concerns. Email security@tunevault.app to schedule.
06

## Network Egress from the Proxy

Exactly two outbound HTTPS connections. No inbound ports. No third parties.

Destination
tunevault.app (US region) — port 443 / HTTPS / TLS 1.2+
Purpose
Delivers health check results to your TuneVault account. JSON payload of Oracle metrics collected during the run.
Authentication
64-hex API key in `X-API-Key` header — generated locally on your server at install time. TuneVault never holds Oracle credentials.
Data sent
Oracle metrics (tablespace usage, wait events, SQL stats). NOT sent: Oracle credentials, schema objects, user data rows.
Destination
tunevault.app/api/proxy/version (same host)
Purpose
Auto-update check every 6 hours. Downloads new binary, validates SHA-256 checksum, replaces in-place. No restart of PM2/systemd required.
Data sent
Current proxy version string only. No credentials, no metrics.
No tunnel software. No inbound connections. The proxy uses standard outbound HTTPS. Your firewall only needs to allow outbound 443 from the Oracle server to `tunevault.app`. No inbound rules, no VPN, no NAT punching.