CresignSys Learn — Lesson 086

Written by

in

Build the CHP Approval & Authorization Engine

The repair engine is now capable of changing a website, but it must not decide by itself whether a repair is authorized.

We therefore add:

REPAIR PLAN
    ↓
VALIDATION
    ↓
AUTHORIZATION
    ↓
APPROVAL
    ↓
REPAIR EXECUTION

This creates a clear security boundary between proposing a change and allowing the change.


1. Why Approval Is Separate

Consider:

PHP:
8.2

Expected:
8.3

CHP can safely determine:

DRIFT

and generate:

RP-000021

But it should not assume:

DRIFT = permission to modify

The operator may have intentionally configured PHP 8.2.

Therefore:

Detection
≠
Authorization

2. Approval Architecture

                    DRIFT
                      │
                      ▼
                REPAIR PLAN
                      │
                      ▼
                 VALIDATION
                      │
                      ▼
                RISK ANALYSIS
                      │
                      ▼
              APPROVAL REQUIRED
                      │
              ┌───────┴───────┐
              ▼               ▼
           APPROVE          REJECT
              │               │
              ▼               ▼
           APPROVED        CANCELLED
              │
              ▼
       hosting-repair

3. New Command

Create:

sudo nano /usr/local/bin/hosting-repair-approve

Usage:

sudo hosting-repair-approve RP-000021

Reject:

sudo hosting-repair-reject RP-000021

For now, approval should be an explicit action.


4. Approval Requirements

Before approval, verify:

Plan exists
Plan is VALID
Site is MANAGED
Plan is not expired
Plan fingerprint is current
Risk policy permits approval
Operator is authorized

Only then:

VALID
 ↓
APPROVED

5. Approval Database

Create:

CREATE TABLE repair_approvals (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    plan_id INTEGER NOT NULL,
    operator_id INTEGER,
    decision TEXT NOT NULL,
    comment TEXT,
    approved_at TEXT NOT NULL,

    FOREIGN KEY (plan_id)
        REFERENCES repair_plans(id)
        ON DELETE CASCADE
);

6. Decision Values

Use:

APPROVED
REJECTED

Later you can add:

DEFERRED
EXPIRED

but don’t need them initially.


7. Why Keep Rejected Approvals?

Suppose:

RP-000021

was rejected.

Don’t simply delete it.

Record:

Plan:
RP-000021

Decision:
REJECTED

Operator:
admin

Comment:
Keep PHP 8.2 for compatibility.

Time:
2026-08-13 17:20

This creates an audit trail.


8. Approval History

A plan can potentially have multiple approval events:

17:00
REJECTED

17:30
new plan created

18:00
APPROVED

Don’t overwrite history.

Each decision should be recorded.


9. But Only One Active Decision

For execution, CHP should determine the latest valid decision.

For example:

APPROVED

followed by:

REJECTED

means the plan must no longer be executable.

The latest decision wins, subject to plan state.


10. Approval State

The repair plan itself can contain:

approval_status

For example:

PENDING
APPROVED
REJECTED

However, keep the detailed history in:

repair_approvals

11. Update repair_plans

Add:

ALTER TABLE repair_plans
ADD COLUMN approval_status TEXT NOT NULL DEFAULT 'PENDING';

Then:

DRAFT
VALID

can have:

approval_status:
PENDING

After approval:

approval_status:
APPROVED

12. Don’t Confuse Plan Status and Approval Status

These are different.

Example:

Plan status:
VALID

Approval:
PENDING

means:

The plan is technically valid but nobody has authorized it yet.

Another:

Plan status:
APPROVED

could mean the approval has been accepted and execution may proceed.

A cleaner model is:

plan status:
VALID

approval status:
APPROVED

Then the execution engine checks both.


13. Authorization vs Approval

These are also different.

Authorization

Is this operator allowed to approve this type of repair?

Approval

Did this operator actually approve this specific repair?

Therefore:

Authorization
     ↓
Can this user approve?
     ↓
Approval
     ↓
Did this user approve?

14. Operator Roles

Create a simple role model.

Start with:

VIEWER
OPERATOR
ADMIN

15. Viewer

Can:

view sites
view health
view reconciliation
view repair plans
view operation history

Cannot:

approve
execute
rollback

16. Operator

Can:

view
create repair plans
approve LOW/MEDIUM repairs
execute approved repairs
view operations

depending on the site’s permissions.


17. Admin

Can:

everything

including:

HIGH-risk approval
management-state changes
user authorization
platform settings

Critical operations should still require stronger controls.


18. Risk-Based Approval

Use:

LOW
MEDIUM
HIGH
CRITICAL

and map them to approval requirements.

Example:

RiskMinimum approval
LOWOperator
MEDIUMOperator
HIGHAdmin
CRITICALManual / restricted

19. PHP Repair

Our current PHP configuration repair:

Risk:
MEDIUM

Therefore:

OPERATOR

may approve it.


20. DNS Repair

A future DNS change:

Risk:
HIGH

requires:

ADMIN

This prevents an ordinary operator from accidentally redirecting a production domain.


21. Database Repair

A database modification:

Risk:
CRITICAL

should not be automatically approved through the basic operator workflow.

Require:

manual administrator authorization

and eventually possibly:

two-person approval

22. Approval Command

For the first CLI implementation:

sudo hosting-repair-approve RP-000021

The command should:

load plan
 ↓
verify plan
 ↓
verify operator
 ↓
verify risk
 ↓
revalidate fingerprint
 ↓
record approval
 ↓
update plan

23. Revalidate Before Approval

Suppose the plan was created at:

16:00

and approval happens at:

17:00

The server may have changed.

Therefore:

hosting-repair-approve

must perform another reconciliation.

If state changed:

PLAN STALE

and approval must stop.


24. Example

Plan:

RP-000021

PHP:
8.2 → 8.3

Current server:

PHP:
8.2

Approval:

VALID

But if the server now has:

PHP:
8.4

then:

Approval:
BLOCKED

Reason:
Plan is stale.

25. Why Approval Must Recheck

Otherwise:

Plan created
    ↓
Server changes
    ↓
Old plan approved
    ↓
Old plan executed

could overwrite a newer administrator decision.


26. Approval Expiration

Approved plans should also have an expiration.

Example:

Approved:
17:00

Expires:
19:00

If execution happens after:

19:00

then:

APPROVAL EXPIRED

Generate a fresh plan.


27. Approval TTL

Add:

approval_expires_at

to the plan.

ALTER TABLE repair_plans
ADD COLUMN approval_expires_at TEXT;

28. Why Approval Expiry?

Consider:

Monday:
approve PHP change

but the operator doesn’t execute it until:

Friday

The server may have changed dramatically.

An old approval should not remain valid indefinitely.


29. Approval Comment

Require a comment for:

HIGH
CRITICAL

Example:

Reason:
Approved after confirming application compatibility.

For LOW-risk operations, a comment can be optional.


30. Approval Example

CresignSys Repair Approval
==========================

Plan:
RP-000021

Site:
example.com

Repair:
PHP 8.2 → 8.3

Risk:
MEDIUM

Plan:
VALID

Fingerprint:
CURRENT

Operator:
admin

Decision:
APPROVED

Expires:
2026-08-13 19:00

31. Rejection Example

CresignSys Repair Approval
==========================

Plan:
RP-000021

Decision:
REJECTED

Reason:
Application currently depends on PHP 8.2.

No changes have been made.

Plan becomes:

CANCELLED

or:

REJECTED

depending on your state model.


32. Better State Model

Use:

DRAFT
VALID
APPROVED
APPLYING
VERIFIED
ROLLED_BACK
FAILED
REJECTED
EXPIRED

Then:

VALID
 ↓
APPROVED

or:

VALID
 ↓
REJECTED

33. Plan Lifecycle

DRAFT
  │
  ▼
VALID
  │
  ├─────────────┐
  ▼             ▼
APPROVED      REJECTED
  │
  ▼
APPLYING
  │
 ┌┴─────────────┐
 ▼              ▼
VERIFIED      ROLLED_BACK
  │
  ▼
COMPLETED

34. Plan Expiration

A plan can move from:

VALID

to:

EXPIRED

if it is not approved within the configured time.

An approved plan can also expire if:

approval_expires_at

has passed.


35. Don’t Reuse Expired Plans

If:

RP-000021

expires:

hosting-repair RP-000021

must reject it.

Correct process:

new reconcile
 ↓
new plan
 ↓
new approval

36. CLI Identity

For the first local implementation, you may use:

id -un

to identify the operating-system user.

Example:

operator:
root

But this is only temporary.

A production web control panel needs its own authenticated identity.


37. Future User Model

Eventually:

users

might contain:

id
username
email
role
status
created_at

and:

site_permissions

could determine which sites an operator can manage.


38. Site-Level Authorization

An operator might be allowed to manage:

example.com
shop.example.com

but only view:

customer-site.com

Therefore authorization needs two dimensions:

WHO
+
WHICH SITE

39. Example

Operator:
John

Role:
OPERATOR

Permissions:
example.com      MANAGE
shop.example.com MANAGE
client.com       VIEW

John can approve:

example.com

but not:

client.com

40. Future Permission Table

CREATE TABLE site_permissions (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    user_id INTEGER NOT NULL,
    site_id INTEGER NOT NULL,
    permission TEXT NOT NULL,

    FOREIGN KEY (user_id)
        REFERENCES users(id),

    FOREIGN KEY (site_id)
        REFERENCES sites(id)
);

Possible permissions:

VIEW
MANAGE
APPROVE
ADMIN

41. Don’t Use Only Global Roles

Avoid:

ADMIN = can modify every site
OPERATOR = can modify every site

as the only authorization mechanism.

Hosting platforms often need:

global role
+
site permission

42. Approval Check

Conceptually:

operator
   ↓
global role
   ↓
site permission
   ↓
risk permission
   ↓
approval allowed?

All four must pass.


43. Approval Decision

For:

RP-000021

the engine should determine:

Operator:
admin

Role:
OPERATOR

Site:
example.com

Permission:
MANAGE

Risk:
MEDIUM

Can approve:
YES

Then:

APPROVED

44. Unauthorized Example

Operator:
viewer

Role:
VIEWER

Site:
example.com

Risk:
MEDIUM

Can approve:
NO

Output:

Approval denied.

Operator does not have permission to approve this repair.

No state change.


45. Audit Everything

Every approval attempt should be logged.

Successful:

APPROVAL:
APPROVED

Denied:

APPROVAL:
DENIED

Even rejected authorization attempts can be valuable security information.


46. Audit Event

Eventually create:

CREATE TABLE audit_events (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    event_type TEXT NOT NULL,
    actor_id INTEGER,
    site_id INTEGER,
    plan_id INTEGER,
    result TEXT NOT NULL,
    message TEXT,
    created_at TEXT NOT NULL
);

Examples:

PLAN_CREATED
PLAN_VALIDATED
APPROVAL_REQUESTED
APPROVAL_GRANTED
APPROVAL_DENIED
REPAIR_STARTED
REPAIR_COMPLETED
REPAIR_ROLLED_BACK

47. Approval and Repair Are Different Actors

This is useful even if you initially use one operator.

Future model:

Operator A:
creates plan

Admin B:
approves

Repair engine:
executes

This provides separation of duties.


48. Two-Person Approval

For high-risk operations:

Operator A:
proposes

Admin B:
approves

Admin C:
second approval

Then:

HIGH-RISK REPAIR
        │
        ▼
 APPROVAL #1
        │
        ▼
 APPROVAL #2
        │
        ▼
      APPLY

Do not implement this yet, but design the database so it remains possible.


49. Multiple Approvals

The existing:

repair_approvals

table supports multiple records:

plan_id | operator | decision
--------|----------|---------
21      | 5        | APPROVED
21      | 7        | APPROVED

Then policy determines whether enough approvals exist.


50. Approval Policy

Eventually:

risk = LOW
required approvals = 1

risk = MEDIUM
required approvals = 1

risk = HIGH
required approvals = 2

risk = CRITICAL
manual intervention

This should be configuration, not hard-coded everywhere.


51. Approval Policy Table

Eventually:

CREATE TABLE approval_policies (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    risk_level TEXT NOT NULL,
    required_approvals INTEGER NOT NULL,
    minimum_role TEXT NOT NULL
);

Example:

LOW       1  OPERATOR
MEDIUM    1  OPERATOR
HIGH      2  ADMIN
CRITICAL  manual

52. Avoid Hard-Coded Permission Logic

Don’t scatter:

if [[ "$RISK" == "HIGH" ]]; then ...

through dozens of scripts.

Use a central function:

check_repair_authorization

and eventually:

get_approval_policy

53. Authorization Library

Create:

sudo nano /etc/cresignsys/lib/authorization.sh

Functions:

get_current_operator
get_operator_role
check_site_permission
get_risk_policy
can_create_plan
can_approve_plan
can_execute_plan

54. Approval Function

Conceptually:

can_approve_plan() {
    local operator="$1"
    local plan_id="$2"

    # verify identity
    # verify site permission
    # verify role
    # verify risk
    # verify plan state
    # verify approval policy
}

Return:

ALLOW
DENY

55. Approval Is Not Execution Permission

This distinction is important.

An operator may be allowed to:

APPROVE

but the system may require:

REPAIR EXECUTOR

to be a restricted service account.

The repair engine itself should run with controlled privileges.


56. Don’t Give the Web UI Root Shell Access

Eventually the web dashboard should not execute:

sudo bash

or arbitrary commands.

Instead:

Web UI
  ↓
CHP API
  ↓
Authorization
  ↓
Structured repair request
  ↓
Repair engine

57. Never Accept Shell Commands From Browser

Bad:

{
  "command": "systemctl restart nginx"
}

Good:

{
  "plan_id": "RP-000021"
}

The backend loads the approved plan.


58. Approval API

Eventually:

POST /api/repair-plans/RP-000021/approve

The server determines:

current user
plan
risk
site
authorization

The browser never tells the server:

who is allowed

The server determines that itself.


59. CSRF and Session Security

When the web interface is introduced, approval operations require:

authenticated session
CSRF protection
authorization check
audit logging

These are not optional for write operations.


60. CLI Safety

For local CLI use, require explicit command:

sudo hosting-repair-approve RP-000021

Do not make:

hosting-repair-plan

automatically approve anything.


61. No Approval Through Environment Variable

Avoid:

CHP_APPROVED=true hosting-repair ...

as a production authorization mechanism.

Approval must exist in the authoritative CHP state.


62. No --force

Avoid:

hosting-repair RP-000021 --force

in the initial system.

A force option tends to become a bypass around safety checks.

If an exceptional override is eventually needed, make it:

explicit
audited
role-restricted
time-limited

63. Approval Expiration Check

Before execution:

current_time < approval_expires_at

If false:

APPROVAL EXPIRED

Then:

REPAIR BLOCKED

64. Approval Fingerprint

Store the fingerprint when approval occurs:

approved_fingerprint

Then the repair engine checks:

current_fingerprint
==
approved_fingerprint

If not:

APPROVAL INVALIDATED

This provides another safety layer.


65. Add to Database

ALTER TABLE repair_plans
ADD COLUMN approved_fingerprint TEXT;

When approval occurs:

approved_fingerprint = current_fingerprint

66. Full Approval Validation

At approval:

Plan:
VALID

Site:
MANAGED

Operator:
AUTHORIZED

Risk:
ALLOWED

Fingerprint:
CURRENT

Approval:
RECORDED

At execution:

Plan:
APPROVED

Approval:
NOT EXPIRED

Fingerprint:
MATCHES

Site:
MANAGED

Reconciliation:
EXPECTED

Proceed.

67. Example End-to-End

16:00
DRIFT detected

16:02
RP-000021 created

16:03
Plan validated

16:05
Operator reviews plan

16:06
Operator approves

16:06
Approval fingerprint recorded

16:07
Repair starts

16:07
Current state rechecked

16:08
Backup created

16:08
Configuration changed

16:08
Nginx validated

16:08
Nginx reloaded

16:09
Health check passed

16:09
Reconciliation passed

16:09
Plan VERIFIED

68. If Something Changes

Suppose:

16:05
Approved

16:06
Administrator manually changes PHP

16:07
Repair starts

The repair engine detects:

fingerprint mismatch

and stops:

REPAIR BLOCKED
PLAN STALE

This prevents CHP from overwriting the administrator’s new configuration.


69. Approval Is a Snapshot

Think of approval as:

"I authorize this exact proposed change to this exact site state."

Not:

"I authorize whatever this plan becomes later."

This is why fingerprints are essential.


70. Lesson 086 — Core Principle

The CHP authorization model is:

WHO
  +
WHAT
  +
WHICH SITE
  +
WHICH RISK
  +
WHICH PLAN
  +
WHICH STATE
  +
WHEN

must all be validated before a repair is executed.

The final flow becomes:

DRIFT
 ↓
REPAIR PLAN
 ↓
VALIDATE
 ↓
AUTHORIZE
 ↓
APPROVE
 ↓
RECHECK STATE
 ↓
BACKUP
 ↓
REPAIR
 ↓
VERIFY

This gives CHP a proper separation between observation, planning, authorization, execution, and verification.


Next Lesson — 087

Build the CHP Backup & Restore Engine

The repair engine now depends on a reliable rollback mechanism.

We will build:

sudo hosting-backup example.com

and:

sudo hosting-restore example.com BACKUP-ID

covering:

Website files
MySQL database
Nginx configuration
SSL metadata
Backup manifest
SHA-256 verification
Retention
Backup integrity
Restore validation

The key architecture will be:

                  BACKUP
                    │
          ┌─────────┴─────────┐
          ▼                   ▼
       FILES                DATABASE
          │                   │
          └─────────┬─────────┘
                    ▼
                MANIFEST
                    │
                    ▼
               CHECKSUMS
                    │
                    ▼
              VERIFIED BACKUP
                    │
                    ▼
                 RESTORE
                    │
                    ▼
              VALIDATE + HEALTH

This backup layer will become the foundation not only for customer backups, but also for safe CHP repairs and automatic rollback.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *