commit de armazens
tests / ci (push) Canceled after 0s

This commit is contained in:
2026-11-04 09:40:26 +02:00
parent e753f7a0a4
commit 63d20b10fc
245 changed files with 10847 additions and 230 deletions
+54
View File
@@ -0,0 +1,54 @@
<?php
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
$settings = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($settings['APP_ENV'] ?? '') !== 'payable-testing' || ($settings['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($settings['HOST_ROOT'] ?? '') !== realpath($root)
|| ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $settings['DB_DATABASE'] ?? '', $matches) || $settings['DB_USERNAME'] !== 'payable_qa_'.$matches[1]) {
throw new LogicException('Wrong pilot destination.');
}
if (! in_array('--apply-authorized', $argv ?? [], true)) {
throw new LogicException('Explicit activation flag required.');
}
$authorization = json_decode(file_get_contents($root.'/docs/proofs/administrative-geography-installation-authorization.json'), true, 32, JSON_THROW_ON_ERROR);
$installation = json_decode(file_get_contents($root.'/docs/proofs/administrative-geography-installation.json'), true, 32, JSON_THROW_ON_ERROR);
$settingsFile = 'C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json';
$before = file_get_contents($settingsFile);
if ($authorization['scope'] !== 'install_two_nullable_geography_columns_and_enable_selection' || $installation['result'] !== 'passed'
|| ! $installation['new_references_all_null'] || ! $installation['restore_database_removed']
|| filter_var($settings['SGC_TWO_FACTOR_ENABLED'] ?? false, FILTER_VALIDATE_BOOLEAN)
|| filter_var($settings['SGC_GEOGRAPHY_ENABLED'] ?? false, FILTER_VALIDATE_BOOLEAN)
|| file_exists($root.'/docs/proofs/administrative-geography-activation.json')) {
throw new LogicException('Activation authorization or current state differs.');
}
$after = [...$settings, 'SGC_GEOGRAPHY_ENABLED' => 'true'];
$protectedBefore = $settings;
$protectedAfter = $after;
unset($protectedBefore['SGC_GEOGRAPHY_ENABLED'], $protectedAfter['SGC_GEOGRAPHY_ENABLED']);
if ($protectedBefore !== $protectedAfter) {
throw new LogicException('Unrelated setting change.');
}
$backup = dirname($installation['backup']).'/settings-before.json';
if (file_put_contents($backup, $before, LOCK_EX) !== strlen($before)) {
throw new RuntimeException('Settings backup failed.');
}
$encoded = json_encode($after, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR).PHP_EOL;
$temporary = $settingsFile.'.geography-'.bin2hex(random_bytes(4)).'.tmp';
if (file_put_contents($temporary, $encoded, LOCK_EX) !== strlen($encoded)) {
throw new RuntimeException('Settings preparation failed.');
}
if (hash_file('sha256', $settingsFile) !== hash('sha256', $before)) {
unlink($temporary);
throw new LogicException('Concurrent setting modification.');
}
if (! rename($temporary, $settingsFile)) {
throw new RuntimeException('Settings activation failed; prepared copy retained privately.');
}
$confirmed = json_decode(file_get_contents($settingsFile), true, 32, JSON_THROW_ON_ERROR);
if ($confirmed !== $after) {
throw new RuntimeException('Settings verification failed.');
}
$result = ['checked_at' => gmdate('c'), 'result' => 'passed', 'environment' => 'http://127.0.0.1:8005', 'authorization' => 'administrative-geography-installation-authorization.json', 'installation' => 'administrative-geography-installation.json', 'changed_setting' => 'SGC_GEOGRAPHY_ENABLED', 'selection_enabled' => true, 'other_settings_preserved' => true, 'settings_backup' => $backup, 'mfa_enabled' => false, 'business_commands' => false, 'automatic_classification' => false];
file_put_contents($root.'/docs/proofs/administrative-geography-activation.json', json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'Geographic selection enabled only in the local pilot; all other settings preserved.'.PHP_EOL;
+18
View File
@@ -0,0 +1,18 @@
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const source = await fs.readFile('scripts/supplier-evaluation-check.mjs', 'utf8');
const common = source.slice(source.indexOf('const base ='), source.indexOf('const author ='));
await new Function('fs', 'assert', 'return (async()=>{' + common + `
const records=[];
for(const role of ['admin','warehouse']) {
const viewer=client(); await viewer.enter(role);
assert.equal((await viewer.request('/contexto','POST',{area:'procurement',option:'procurement.internal'})).status,302);
for(const path of ['/auditoria/eventos','/auditoria/eventos.csv']) {
const result=await viewer.request(path,'GET',undefined,false);
assert.equal(result.status,403);
records.push({role,path,status:result.status});
}
}
await fs.writeFile('docs/proofs/audit-metadata-http.json',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',records,pilot_grants_changed:false,business_commands:false,visual_review:false,coverage:'Denial before explicit permission; positive access exercised in disposable databases.'},null,2));
console.log('Auditoria recusa acesso no piloto sem nova competência explícita.');
` + '})()')(fs, assert);
+12
View File
@@ -0,0 +1,12 @@
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const source = await fs.readFile('scripts/supplier-evaluation-check.mjs', 'utf8');
const proofName = process.argv.includes('--additional') ? 'candidate-additional-geography-http.json' : 'candidate-geography-http.json';
const common = source.slice(source.indexOf('const base ='), source.indexOf('const author ='));
await new Function('fs','assert','return (async()=>{'+common+`
const guest=await fetch(base+'/candidaturas/1/divisao-administrativa',{headers:{Accept:'application/json'},redirect:'manual'}); assert.equal(guest.status,401);
const staff=client(); await staff.enter('admin'); assert.equal((await staff.request('/contexto','POST',{area:'procurement',option:'procurement.internal'})).status,302); const denied=await staff.request('/candidaturas/1/divisao-administrativa','GET',undefined,false); assert.equal(denied.status,401);
const catalogue=await staff.request('/api/divisao-administrativa'); assert.equal(catalogue.status,200); assert.equal(catalogue.page.data.length,11);
await fs.writeFile('docs/proofs/${proofName}',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',guest_status:401,staff_without_candidate_status:401,existing_staff_catalogue_status:200,registration_commands:false,profile_commands:false,portal_configuration_commands:false,business_commands:false,mfa_activation:false,positive_candidate_session_coverage:'disposable tests only',visual_review:false},null,2));
console.log('Candidate catalogue denied to guests and staff-only sessions; no candidate registration or profile changes.');
`+'})()')(fs,assert);
@@ -0,0 +1,57 @@
<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
$settings = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($settings['APP_ENV'] ?? '') !== 'payable-testing' || ($settings['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($settings['HOST_ROOT'] ?? '') !== realpath($root)
|| ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $settings['DB_DATABASE'] ?? '', $matches) || $settings['DB_USERNAME'] !== 'payable_qa_'.$matches[1]) {
throw new LogicException('Wrong pilot destination.');
}
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$base = DB::connection('pgsql')->getConfig();
unset($base['name']);
config(['database.connections.geography_pilot_read' => [...$base, 'url' => null, 'host' => $settings['DB_HOST'], 'port' => $settings['DB_PORT'],
'database' => $settings['DB_DATABASE'], 'username' => $settings['DB_USERNAME'], 'password' => $settings['DB_PASSWORD']]]);
$db = DB::connection('geography_pilot_read');
$result = $db->transaction(function () use ($db, $settings) {
$db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $settings['DB_DATABASE'] || $identity->role !== $settings['DB_USERNAME']) {
throw new LogicException('Identity mismatch.');
}
$schema = Schema::connection('geography_pilot_read');
return ['checked_at' => gmdate('c'), 'environment' => 'http://127.0.0.1:8005', 'result' => 'passed',
'candidate_accounts' => $db->table('candidate_accounts')->count(),
'candidate_profile_versions' => $db->table('candidate_profile_versions')->count(),
'candidate_portals_configured' => $db->table('candidate_portal_versions')->count(),
'warehouse_column_installed' => $schema->hasColumn('warehouses', 'geography_reference'),
'equipment_column_installed' => $schema->hasColumn('equipment', 'geography_reference'),
'operational_flag' => filter_var($settings['SGC_OPERATIONAL_GEOGRAPHY_ENABLED'] ?? false, FILTER_VALIDATE_BOOLEAN),
'operational_migration_applied' => $db->table('migrations')->where('migration', '2026_11_03_000005_add_operational_geography_references')->exists(),
'supplier_column_installed' => $schema->hasColumn('suppliers', 'geography_reference'),
'company_column_installed' => $schema->hasColumn('tenants', 'geography_reference'),
'migration_applied' => $db->table('migrations')->where('migration', '2026_11_03_000004_add_administrative_geography_references')->exists(),
'mfa_accounts_enrolled' => $db->table('users')->where(fn ($q) => $q->whereNotNull('two_factor_secret')->orWhereNotNull('two_factor_recovery_codes')->orWhereNotNull('two_factor_confirmed_at'))->count(),
'access_version' => (int) $db->table('organization_access')->where('tenant_id', 1)->value('version'),
'business_commands' => false, 'geography_flag' => filter_var($settings['SGC_GEOGRAPHY_ENABLED'] ?? false, FILTER_VALIDATE_BOOLEAN),
'classified_suppliers' => $db->table('suppliers')->whereNotNull('geography_reference')->count(),
'classified_companies' => $db->table('tenants')->whereNotNull('geography_reference')->count()];
});
if (! $result['migration_applied'] || ! $result['geography_flag'] || $result['warehouse_column_installed'] || $result['equipment_column_installed'] || $result['operational_migration_applied'] || $result['operational_flag'] || $result['mfa_accounts_enrolled']) {
throw new LogicException('Pilot differs from the expected operational geography preparation scope.');
}
$proofName = match (true) {
in_array('--received-availability', $argv ?? [], true) => 'received-availability-pilot.json',
in_array('--territory', $argv ?? [], true) => 'candidate-territory-pilot.json',
in_array('--additional', $argv ?? [], true) => 'candidate-additional-geography-pilot.json',
default => 'candidate-geography-pilot.json',
};
file_put_contents($root.'/docs/proofs/'.$proofName, json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'Candidate geography checked read-only: no profile or portal commands; operational geography remains pending.'.PHP_EOL;
+14
View File
@@ -0,0 +1,14 @@
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const source=await fs.readFile('scripts/supplier-evaluation-check.mjs','utf8');
const common=source.slice(source.indexOf('const base ='),source.indexOf('const author ='));
await new Function('fs','assert','return (async()=>{'+common+`
const viewer=client(); await viewer.enter('admin');
assert.equal((await viewer.request('/contexto','POST',{area:'people',option:'people.internal'})).status,302);
const index=await viewer.request('/pessoas'); assert.equal(index.status,200);
const missing=await viewer.request('/pessoas/999999/divisao-administrativa','GET',undefined,false); assert.equal(missing.status,404);
assert.equal((await viewer.request('/api/divisao-administrativa','GET',undefined,false)).status,403);
let inboxes=0; for(const record of index.page.props.processes.data.slice(0,2)) { const page=await viewer.request('/pessoas/'+record.id+'/recebidas'); if(page.status===200) { assert.equal(page.page.props.geographyEnabled,true); inboxes++; } else { assert.equal(page.status,403); } }
await fs.writeFile('docs/proofs/candidate-territory-http.json',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',people_index_status:200,unknown_process_catalogue_status:404,procurement_catalogue_in_people_context_status:403,visible_inboxes_checked:inboxes,business_commands:false,process_or_portal_created:false,profile_commands:false,triage_commands:false,visual_review:false,positive_process_filter_coverage:'disposable tests'},null,2));
console.log('People access remains scoped; no new processes, profiles or triage decisions.');
`+'})()')(fs,assert);
+24
View File
@@ -0,0 +1,24 @@
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const source = await fs.readFile('scripts/supplier-evaluation-check.mjs', 'utf8');
const common = source.slice(source.indexOf('const base ='), source.indexOf('const author ='));
await new Function('fs', 'assert', 'return (async()=>{' + common + `
const records=[];
for(const role of ['admin','warehouse']) {
const viewer=client(); await viewer.enter(role);
assert.equal((await viewer.request('/contexto','POST',{area:'procurement',option:'procurement.internal'})).status,302);
const index=await viewer.request('/equipamentos'); assert.equal(index.status,200);
let detailsChecked=0;
for(const equipment of index.page.props.equipment.slice(0,2)) {
const detail=await viewer.request('/equipamentos/'+equipment.id); assert.equal(detail.status,200);
assert.equal(detail.page.props.equipment.id,equipment.id);
assert.ok(Array.isArray(detail.page.props.purchases.data));
assert.ok(Array.isArray(detail.page.props.movements.data));
assert.ok(detail.page.props.movements.data.every(row=>row.snapshot===undefined));
detailsChecked++;
}
records.push({role,detailsChecked});
}
await fs.writeFile('docs/proofs/equipment-integration-http.json',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',records,business_commands:false,grants_changed:false,visual_review:false,coverage:'Existing equipment only; complete native journeys exercised in disposable databases.'},null,2));
console.log('Equipamentos consultados no piloto; sem novas compras ou movimentos.');
` + '})()')(fs, assert);
+21
View File
@@ -0,0 +1,21 @@
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const source = await fs.readFile('scripts/supplier-evaluation-check.mjs', 'utf8');
const common = source.slice(source.indexOf('const base ='), source.indexOf('const author ='));
await new Function('fs', 'assert', 'return (async()=>{' + common + `
const records=[];
for(const role of ['admin','procurement','finance']) {
const viewer=client(); await viewer.enter(role);
assert.equal((await viewer.request('/contexto','POST',{area:'procurement',option:'procurement.internal'})).status,302);
const suppliers=await viewer.request('/fornecedores'); assert.equal(suppliers.status,200); assert.equal(suppliers.page.props.geographyEnabled,true);
const catalogue=await viewer.request('/api/divisao-administrativa'); assert.equal(catalogue.status,200); assert.equal(catalogue.page.data.length,11);
assert.equal((await viewer.request('/api/divisao-administrativa?parent=2')).status,200);
const supplier=suppliers.page.props.suppliers.data[0]; assert.ok(supplier); assert.equal(supplier.geography_reference,null);
const detail=await viewer.request('/fornecedores/'+supplier.id); assert.equal(detail.status,200); assert.equal(detail.page.props.geography,null);
if(role==='procurement') { const edit=await viewer.request('/fornecedores/'+supplier.id+'/editar'); assert.equal(edit.status,200); assert.equal(edit.page.props.geographyEnabled,true); }
if(role==='admin') { const parameters=await viewer.request('/administracao/parametrizacao'); assert.equal(parameters.status,200); assert.equal(parameters.page.props.geographyEnabled,true); assert.equal(parameters.page.props.geography,null); }
records.push({role,geographicSelectionAvailable:true,existingSupplierUnclassified:true});
}
await fs.writeFile('docs/proofs/administrative-geography-installation-http.json',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',records,business_commands:false,classification_commands:false,approval_changes:false,mfa_activation:false,visual_review:false},null,2));
console.log('Geographic selection available in company and supplier pages; no classification submitted.');
` + '})()')(fs, assert);
@@ -0,0 +1,43 @@
<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
$settings = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($settings['APP_ENV'] ?? '') !== 'payable-testing' || ($settings['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($settings['HOST_ROOT'] ?? '') !== realpath($root)
|| ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $settings['DB_DATABASE'] ?? '', $matches) || $settings['DB_USERNAME'] !== 'payable_qa_'.$matches[1]) {
throw new LogicException('Wrong pilot destination.');
}
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$base = DB::connection('pgsql')->getConfig();
unset($base['name']);
config(['database.connections.geography_pilot_read' => [...$base, 'url' => null, 'host' => $settings['DB_HOST'], 'port' => $settings['DB_PORT'],
'database' => $settings['DB_DATABASE'], 'username' => $settings['DB_USERNAME'], 'password' => $settings['DB_PASSWORD']]]);
$db = DB::connection('geography_pilot_read');
$result = $db->transaction(function () use ($db, $settings) {
$db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $settings['DB_DATABASE'] || $identity->role !== $settings['DB_USERNAME']) {
throw new LogicException('Identity mismatch.');
}
$schema = Schema::connection('geography_pilot_read');
return ['checked_at' => gmdate('c'), 'environment' => 'http://127.0.0.1:8005', 'result' => 'passed',
'supplier_column_installed' => $schema->hasColumn('suppliers', 'geography_reference'),
'company_column_installed' => $schema->hasColumn('tenants', 'geography_reference'),
'migration_applied' => $db->table('migrations')->where('migration', '2026_11_03_000004_add_administrative_geography_references')->exists(),
'mfa_accounts_enrolled' => $db->table('users')->where(fn ($q) => $q->whereNotNull('two_factor_secret')->orWhereNotNull('two_factor_recovery_codes')->orWhereNotNull('two_factor_confirmed_at'))->count(),
'access_version' => (int) $db->table('organization_access')->where('tenant_id', 1)->value('version'),
'business_commands' => false, 'geography_flag' => filter_var($settings['SGC_GEOGRAPHY_ENABLED'] ?? false, FILTER_VALIDATE_BOOLEAN),
'classified_suppliers' => $db->table('suppliers')->whereNotNull('geography_reference')->count(),
'classified_companies' => $db->table('tenants')->whereNotNull('geography_reference')->count()];
});
if (! $result['migration_applied'] || ! $result['supplier_column_installed'] || ! $result['company_column_installed'] || $result['mfa_accounts_enrolled'] || ! $result['geography_flag'] || $result['classified_suppliers'] || $result['classified_companies']) {
throw new LogicException('Pilot differs from the authorized installed and unclassified geography scope.');
}
file_put_contents($root.'/docs/proofs/administrative-geography-installation-pilot.json', json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'Geography pilot inspected read-only: columns empty and selection enabled; no business commands.'.PHP_EOL;
+41
View File
@@ -0,0 +1,41 @@
<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
$settings = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($settings['APP_ENV'] ?? '') !== 'payable-testing' || ($settings['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($settings['HOST_ROOT'] ?? '') !== realpath($root)
|| ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $settings['DB_DATABASE'] ?? '', $matches) || $settings['DB_USERNAME'] !== 'payable_qa_'.$matches[1]) {
throw new LogicException('Wrong pilot destination.');
}
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$base = DB::connection('pgsql')->getConfig();
unset($base['name']);
config(['database.connections.geography_pilot_read' => [...$base, 'url' => null, 'host' => $settings['DB_HOST'], 'port' => $settings['DB_PORT'],
'database' => $settings['DB_DATABASE'], 'username' => $settings['DB_USERNAME'], 'password' => $settings['DB_PASSWORD']]]);
$db = DB::connection('geography_pilot_read');
$result = $db->transaction(function () use ($db, $settings) {
$db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $settings['DB_DATABASE'] || $identity->role !== $settings['DB_USERNAME']) {
throw new LogicException('Identity mismatch.');
}
$schema = Schema::connection('geography_pilot_read');
return ['checked_at' => gmdate('c'), 'environment' => 'http://127.0.0.1:8005', 'result' => 'passed',
'supplier_column_installed' => $schema->hasColumn('suppliers', 'geography_reference'),
'company_column_installed' => $schema->hasColumn('tenants', 'geography_reference'),
'migration_applied' => $db->table('migrations')->where('migration', '2026_11_03_000004_add_administrative_geography_references')->exists(),
'mfa_accounts_enrolled' => $db->table('users')->where(fn ($q) => $q->whereNotNull('two_factor_secret')->orWhereNotNull('two_factor_recovery_codes')->orWhereNotNull('two_factor_confirmed_at'))->count(),
'access_version' => (int) $db->table('organization_access')->where('tenant_id', 1)->value('version'),
'business_commands' => false, 'geography_flag' => config('geography.enabled')];
});
if ($result['migration_applied'] || $result['supplier_column_installed'] || $result['company_column_installed'] || $result['mfa_accounts_enrolled'] || $result['geography_flag']) {
throw new LogicException('Pilot differs from the expected uninstalled geography scope.');
}
file_put_contents($root.'/docs/proofs/administrative-geography-pilot.json', json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'Geography pilot inspected read-only: columns absent; no business commands.'.PHP_EOL;
+17
View File
@@ -0,0 +1,17 @@
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const source = await fs.readFile('scripts/supplier-evaluation-check.mjs', 'utf8');
const common = source.slice(source.indexOf('const base ='), source.indexOf('const author ='));
await new Function('fs', 'assert', 'return (async()=>{' + common + `
const records=[];
const admin=client(); await admin.enter('admin');
assert.equal((await admin.request('/contexto','POST',{area:'procurement',option:'procurement.internal'})).status,302);
const page=await admin.request('/administracao/divisao-administrativa'); assert.equal(page.status,200); assert.equal(page.page.props.total,10729); assert.equal(page.page.props.records.length,50); assert.equal(page.page.encryptHistory,true);
const filtered=await admin.request('/administracao/divisao-administrativa?issue=blank_designation'); assert.equal(filtered.status,200); assert.equal(filtered.page.props.total,9);
const exported=await admin.request('/administracao/divisao-administrativa.csv?issue=blank_designation','GET',undefined,false); assert.equal(exported.status,200); assert.ok(exported.text.startsWith('Linha,ID,Provincia'));
const buyer=client(); await buyer.enter('procurement'); await buyer.request('/contexto','POST',{area:'procurement',option:'procurement.internal'}); assert.equal((await buyer.request('/administracao/divisao-administrativa','GET',undefined,false)).status,403);
records.push({role:'admin',pendingRecords:10729,firstPage:50,blankDesignations:9,exportStatus:200});
records.push({role:'procurement',reviewStatus:403});
await fs.writeFile('docs/proofs/administrative-geography-review-http.json',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',records,business_commands:false,classification_commands:false,approval_changes:false,mfa_activation:false,visual_review:false},null,2));
console.log('Administrative review and filtered CSV checked read-only; no geography or entity changes.');
` + '})()')(fs, assert);
+155
View File
@@ -0,0 +1,155 @@
<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Laravel\Fortify\Features;
use Symfony\Component\Process\Process;
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
if (! in_array('--apply-authorized', $argv, true)) {
throw new LogicException('Explicit preparation flag required.');
}
$s = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($s['APP_ENV'] ?? '') !== 'payable-testing' || ($s['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($s['HOST_ROOT'] ?? '') !== realpath($root) || ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $s['DB_DATABASE'] ?? '', $m) || $s['DB_USERNAME'] !== 'payable_qa_'.$m[1]) {
throw new LogicException('Wrong pilot destination.');
}
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$owner = DB::connection('pgsql')->getConfig();
unset($owner['name']);
if ($owner['host'] !== '127.0.0.1') {
throw new LogicException('Local server required.');
}
$qa = [...$owner, 'url' => null, 'database' => $s['DB_DATABASE'], 'username' => $s['DB_USERNAME'], 'password' => $s['DB_PASSWORD']];
config(['database.connections.receipt_install' => $qa, 'database.connections.receipt_owner' => [...$owner, 'url' => null, 'database' => 'postgres']]);
DB::setDefaultConnection('receipt_install');
$db = DB::connection();
$admin = DB::connection('receipt_owner');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $s['DB_DATABASE'] || $identity->role !== $s['DB_USERNAME']) {
throw new LogicException('Identity mismatch.');
}
$fingerprint = function ($connection, $tables) {
$out = [];
foreach ($tables as $table) {
$rows = $connection->select('select row_to_json(t)::text as row from "'.str_replace('"', '""', $table).'" t order by row_to_json(t)::text');
$out[$table] = hash('sha256', json_encode(array_column($rows, 'row'), JSON_THROW_ON_ERROR));
}
return $out;
};
$pg = function ($binary, $args, $connection) {
$p = new Process(['C:/Program Files/PostgreSQL/17/bin/'.$binary.'.exe', ...$args], null, ['PGHOST' => $connection['host'], 'PGPORT' => (string) $connection['port'], 'PGUSER' => $connection['username'], 'PGPASSWORD' => $connection['password']], timeout: 120);
$p->run();
if (! $p->isSuccessful()) {
throw new RuntimeException('Backup/restore failed.');
}
};
$tables = array_column($db->select("select tablename from pg_tables where schemaname='public' order by tablename"), 'tablename');
$migration = 'database/migrations/2026_11_03_000004_add_administrative_geography_references.php';
$authorization = json_decode(file_get_contents($root.'/docs/proofs/administrative-geography-installation-authorization.json'), true, 32, JSON_THROW_ON_ERROR);
if ($authorization['scope'] !== 'install_two_nullable_geography_columns_and_enable_selection'
|| $authorization['environment'] !== 'http://127.0.0.1:8005'
|| $authorization['proposal_sha256'] !== hash_file('sha256', $root.'/docs/proposta-instalacao-geografia.md')
|| $authorization['migration_sha256'] !== hash_file('sha256', $root.'/'.$migration)
|| file_exists($root.'/docs/proofs/administrative-geography-installation.json')
|| Features::enabled(Features::twoFactorAuthentication())
|| filter_var($s['SGC_TWO_FACTOR_ENABLED'] ?? false, FILTER_VALIDATE_BOOLEAN)
|| filter_var($s['SGC_GEOGRAPHY_ENABLED'] ?? false, FILTER_VALIDATE_BOOLEAN)) {
throw new LogicException('Authorization or pilot state does not match empty geography installation.');
}
foreach (['tenants', 'suppliers'] as $table) {
if (Schema::connection('receipt_install')->hasColumn($table, 'geography_reference')) {
throw new LogicException('Geography schema already present; inspect proof instead of repeating.');
}
}
$oldColumns = [];
foreach (['tenants', 'suppliers'] as $table) {
$oldColumns[$table] = Schema::connection('receipt_install')->getColumnListing($table);
}
$projected = function ($connection) use ($oldColumns) {
$out = [];
foreach ($oldColumns as $table => $columns) {
$selected = implode(',', array_map(fn ($c) => '"'.str_replace('"', '""', $c).'"', $columns));
$rows = $connection->select('select row_to_json(t)::text as row from (select '.$selected.' from "'.$table.'") t order by row_to_json(t)::text');
$out[$table] = hash('sha256', json_encode(array_column($rows, 'row'), JSON_THROW_ON_ERROR));
}
return $out;
};
$checkEmpty = function ($connection, $name) use ($tables, $oldColumns) {
foreach ($oldColumns as $table => $columns) {
if (Schema::connection($name)->getColumnListing($table) !== [...$columns, 'geography_reference']
|| $connection->table($table)->whereNotNull('geography_reference')->exists()) {
throw new LogicException('Unexpected geography structure or nonempty references.');
}
}
if (array_column($connection->select("select tablename from pg_tables where schemaname='public' order by tablename"), 'tablename') !== $tables) {
throw new LogicException('Unexpected table created.');
}
};
$restore = 'compras_pilot_restore_'.bin2hex(random_bytes(6));
$created = false;
try {
$db->beginTransaction();
$db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ');
$baseline = $fingerprint($db, $tables);
$beforeRows = $projected($db);
$migrationCount = $db->table('migrations')->count();
$directory = 'C:/laragon/data/sgf-tempo/backups/compras-geography-installation-'.gmdate('Ymd-His').'-'.bin2hex(random_bytes(3));
if (! mkdir($directory, 0700, true)) {
throw new RuntimeException('Backup unavailable.');
}
$dump = $directory.'/before.dump';
$snapshot = $db->selectOne('select pg_export_snapshot() as snapshot')->snapshot;
$pg('pg_dump', ['--format=custom', '--snapshot='.$snapshot, '--file='.$dump, '--dbname='.$qa['database']], $qa);
$db->commit();
$admin->statement('CREATE DATABASE "'.$restore.'"');
$created = true;
$pg('pg_restore', ['--no-owner', '--no-privileges', '--exit-on-error', '--dbname='.$restore, $dump], $owner);
config(['database.connections.receipt_restore' => [...$owner, 'url' => null, 'database' => $restore]]);
$restored = DB::connection('receipt_restore');
if ($fingerprint($restored, $tables) !== $baseline) {
throw new LogicException('Restored backup differs.');
}
if (Artisan::call('migrate', ['--database' => 'receipt_restore', '--path' => $migration, '--force' => true]) !== 0) {
throw new RuntimeException('Disposable migration failed.');
}
$protected = array_values(array_diff($tables, ['tenants', 'suppliers', 'migrations']));
$checkEmpty($restored, 'receipt_restore');
if ($fingerprint($restored, $protected) !== array_intersect_key($baseline, array_flip($protected)) || $projected($restored) !== $beforeRows || $restored->table('migrations')->count() !== $migrationCount + 1) {
throw new LogicException('Unexpected dry-run changes.');
}
$db->transaction(function () use ($db, $tables, $baseline, $fingerprint, $migration, $protected, $projected, $beforeRows, $migrationCount, $checkEmpty) {
$db->statement("SET LOCAL lock_timeout = '5s'");
foreach ($tables as $table) {
$db->statement('LOCK TABLE "'.str_replace('"', '""', $table).'" IN SHARE MODE');
}
if ($fingerprint($db, $tables) !== $baseline) {
throw new LogicException('Pilot changed after backup; abort.');
}
if (Artisan::call('migrate', ['--database' => 'receipt_install', '--path' => $migration, '--force' => true]) !== 0) {
throw new RuntimeException('Pilot migration failed.');
}
$checkEmpty($db, 'receipt_install');
if ($fingerprint($db, $protected) !== array_intersect_key($baseline, array_flip($protected)) || $projected($db) !== $beforeRows || $db->table('migrations')->count() !== $migrationCount + 1) {
throw new LogicException('Unexpected pilot changes.');
}
});
$result = ['checked_at' => gmdate('c'), 'result' => 'passed', 'environment' => 'http://127.0.0.1:8005', 'scope' => $authorization['scope'], 'migration' => $migration, 'migration_sha256' => hash_file('sha256', $root.'/'.$migration), 'backup' => $dump, 'backup_sha256' => hash_file('sha256', $dump), 'restored_tables_checked' => count($tables), 'protected_tables_checked' => count($protected), 'existing_company_and_supplier_columns_preserved' => true, 'new_references_all_null' => true, 'pilot_migration_applied' => true, 'feature_activated' => false, 'mfa_enabled' => false, 'passwords_or_grants_changed' => false, 'restore_database_removed' => false];
} finally {
if ($db->transactionLevel() > 0) {
$db->rollBack();
}
DB::purge('receipt_restore');
if ($created) {
$admin->statement('DROP DATABASE "'.$restore.'" WITH (FORCE)');
}
}
$result['restore_database_removed'] = true;
file_put_contents($root.'/docs/proofs/administrative-geography-installation.json', json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'Two empty geography columns installed; all prior values preserved; activation remains separate.'.PHP_EOL;
+138
View File
@@ -0,0 +1,138 @@
<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Laravel\Fortify\Features;
use Symfony\Component\Process\Process;
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
if (! in_array('--apply-authorized', $argv, true)) {
throw new LogicException('Explicit preparation flag required.');
}
$s = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($s['APP_ENV'] ?? '') !== 'payable-testing' || ($s['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($s['HOST_ROOT'] ?? '') !== realpath($root) || ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $s['DB_DATABASE'] ?? '', $m) || $s['DB_USERNAME'] !== 'payable_qa_'.$m[1]) {
throw new LogicException('Wrong pilot destination.');
}
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$owner = DB::connection('pgsql')->getConfig();
unset($owner['name']);
if ($owner['host'] !== '127.0.0.1') {
throw new LogicException('Local server required.');
}
$qa = [...$owner, 'url' => null, 'database' => $s['DB_DATABASE'], 'username' => $s['DB_USERNAME'], 'password' => $s['DB_PASSWORD']];
config(['database.connections.receipt_install' => $qa, 'database.connections.receipt_owner' => [...$owner, 'url' => null, 'database' => 'postgres']]);
DB::setDefaultConnection('receipt_install');
$db = DB::connection();
$admin = DB::connection('receipt_owner');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $s['DB_DATABASE'] || $identity->role !== $s['DB_USERNAME']) {
throw new LogicException('Identity mismatch.');
}
$fingerprint = function ($connection, $tables) {
$out = [];
foreach ($tables as $table) {
$rows = $connection->select('select row_to_json(t)::text as row from "'.str_replace('"', '""', $table).'" t order by row_to_json(t)::text');
$out[$table] = hash('sha256', json_encode(array_column($rows, 'row'), JSON_THROW_ON_ERROR));
}
return $out;
};
$pg = function ($binary, $args, $connection) {
$p = new Process(['C:/Program Files/PostgreSQL/17/bin/'.$binary.'.exe', ...$args], null, ['PGHOST' => $connection['host'], 'PGPORT' => (string) $connection['port'], 'PGUSER' => $connection['username'], 'PGPASSWORD' => $connection['password']], timeout: 120);
$p->run();
if (! $p->isSuccessful()) {
throw new RuntimeException('Backup/restore failed.');
}
};
$tables = array_column($db->select("select tablename from pg_tables where schemaname='public' order by tablename"), 'tablename');
$migration = 'database/migrations/2026_11_03_000001_add_two_factor_columns_to_users.php';
$proposalFile = $root.'/docs/proofs/mfa-pilot-schema-proposal.json';
$authorization = json_decode(ltrim(file_get_contents($root.'/docs/proofs/mfa-pilot-schema-authorization.json'), "\xEF\xBB\xBF"), true, 32, JSON_THROW_ON_ERROR);
$proposal = json_decode(ltrim(file_get_contents($proposalFile), "\xEF\xBB\xBF"), true, 32, JSON_THROW_ON_ERROR);
if ($authorization['proposal_sha256'] !== hash_file('sha256', $proposalFile) || $authorization['scope'] !== 'install_nullable_mfa_columns_only' || $authorization['environment'] !== 'http://127.0.0.1:8005' || $proposal['migration_sha256'] !== hash_file('sha256', $root.'/'.$migration) || file_exists($root.'/docs/proofs/mfa-pilot-schema-installation.json') || Features::enabled(Features::twoFactorAuthentication()) || filter_var($s['SGC_TWO_FACTOR_ENABLED'] ?? false, FILTER_VALIDATE_BOOLEAN)) {
throw new LogicException('Wrong authorization, destination, feature state or already installed.');
}
foreach (['two_factor_secret', 'two_factor_recovery_codes', 'two_factor_confirmed_at'] as $column) {
if (Schema::connection('receipt_install')->hasColumn('users', $column)) {
throw new LogicException('MFA schema already exists; inspect before repeating.');
}
}
$restore = 'compras_pilot_restore_'.bin2hex(random_bytes(6));
$created = false;
try {
$db->beginTransaction();
$db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ');
$baseline = $fingerprint($db, $tables);
$directory = 'C:/laragon/data/sgf-tempo/backups/compras-mfa-installation-'.gmdate('Ymd-His').'-'.bin2hex(random_bytes(3));
if (! mkdir($directory, 0700, true)) {
throw new RuntimeException('Backup unavailable.');
}
$dump = $directory.'/before.dump';
$snapshot = $db->selectOne('select pg_export_snapshot() as snapshot')->snapshot;
$pg('pg_dump', ['--format=custom', '--snapshot='.$snapshot, '--file='.$dump, '--dbname='.$qa['database']], $qa);
$db->commit();
$admin->statement('CREATE DATABASE "'.$restore.'"');
$created = true;
$pg('pg_restore', ['--no-owner', '--no-privileges', '--exit-on-error', '--dbname='.$restore, $dump], $owner);
config(['database.connections.receipt_restore' => [...$owner, 'url' => null, 'database' => $restore]]);
$restored = DB::connection('receipt_restore');
if ($fingerprint($restored, $tables) !== $baseline) {
throw new LogicException('Restored backup differs.');
}
$columns = Schema::connection('receipt_restore')->getColumnListing('users');
$userRows = function ($connection) use ($columns) {
$selected = implode(',', array_map(fn ($c) => '"'.str_replace('"', '""', $c).'"', $columns));
return $connection->select('select row_to_json(t)::text as row from (select '.$selected.' from users) t order by row_to_json(t)::text');
};
$beforeUsers = $userRows($restored);
$migrationCount = $restored->table('migrations')->count();
if (Artisan::call('migrate', ['--database' => 'receipt_restore', '--path' => $migration, '--force' => true]) !== 0) {
throw new RuntimeException('Disposable migration failed.');
}
$protected = array_values(array_diff($tables, ['users', 'migrations']));
if ($fingerprint($restored, $protected) !== array_intersect_key($baseline, array_flip($protected)) || $userRows($restored) != $beforeUsers || $restored->table('migrations')->count() !== $migrationCount + 1) {
throw new LogicException('Unexpected migration changes.');
}
foreach (['two_factor_secret', 'two_factor_recovery_codes', 'two_factor_confirmed_at'] as $column) {
if ($restored->table('users')->whereNotNull($column)->exists()) {
throw new LogicException('Unexpected enrollment data.');
}
}
$db->transaction(function () use ($db, $tables, $baseline, $fingerprint, $migration, $protected, $userRows, $beforeUsers, $migrationCount) {
$db->statement("SET LOCAL lock_timeout = '5s'");
foreach ($tables as $table) {
$db->statement('LOCK TABLE "'.str_replace('"', '""', $table).'" IN SHARE MODE');
}
if ($fingerprint($db, $tables) !== $baseline) {
throw new LogicException('Pilot changed after backup; abort.');
}
if (Artisan::call('migrate', ['--database' => 'receipt_install', '--path' => $migration, '--force' => true]) !== 0) {
throw new RuntimeException('Pilot migration failed.');
}
if ($fingerprint($db, $protected) !== array_intersect_key($baseline, array_flip($protected)) || $userRows($db) != $beforeUsers || $db->table('migrations')->count() !== $migrationCount + 1) {
throw new LogicException('Pilot values changed unexpectedly.');
}
foreach (['two_factor_secret', 'two_factor_recovery_codes', 'two_factor_confirmed_at'] as $column) {
if ($db->table('users')->whereNotNull($column)->exists()) {
throw new LogicException('Fields not empty.');
}
}
});
$result = ['checked_at' => gmdate('c'), 'result' => 'passed', 'environment' => 'http://127.0.0.1:8005', 'scope' => 'install_nullable_mfa_columns_only', 'migration' => $migration, 'migration_sha256' => hash_file('sha256', $root.'/'.$migration), 'backup' => $dump, 'backup_sha256' => hash_file('sha256', $dump), 'restored_tables_checked' => count($tables), 'protected_tables_checked' => count($protected), 'existing_user_columns_preserved' => true, 'existing_users' => $restored->table('users')->count(), 'enrollment_created' => false, 'pilot_migration_applied' => true, 'pilot_configuration_changed' => false, 'passwords_or_grants_changed' => false, 'restore_database_removed' => false];
} finally {
if ($db->transactionLevel() > 0) {
$db->rollBack();
}
DB::purge('receipt_restore');
if ($created) {
$admin->statement('DROP DATABASE "'.$restore.'" WITH (FORCE)');
}
}
$result['restore_database_removed'] = true;
file_put_contents($root.'/docs/proofs/mfa-pilot-schema-installation.json', json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'Three empty MFA fields installed; feature remains disabled.'.PHP_EOL;
+106 -49
View File
@@ -1,63 +1,120 @@
<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\Process\Process;
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
if (!in_array('--apply-authorized', $argv, true)) { throw new LogicException('Explicit authorized installation required.'); }
if (! in_array('--apply-authorized', $argv, true)) {
throw new LogicException('Explicit authorized installation required.');
}
$s = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($s['APP_ENV'] ?? '') !== 'payable-testing' || ($s['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($s['HOST_ROOT'] ?? '') !== realpath($root) || !preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $s['DB_DATABASE'] ?? '', $m) || $s['DB_USERNAME'] !== 'payable_qa_'.$m[1]) { throw new LogicException('Wrong pilot destination.'); }
if (($s['APP_ENV'] ?? '') !== 'payable-testing' || ($s['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($s['HOST_ROOT'] ?? '') !== realpath($root) || ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $s['DB_DATABASE'] ?? '', $m) || $s['DB_USERNAME'] !== 'payable_qa_'.$m[1]) {
throw new LogicException('Wrong pilot destination.');
}
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$owner = DB::connection('pgsql')->getConfig(); unset($owner['name']);
if ($owner['host'] !== '127.0.0.1') { throw new LogicException('Local server required.'); }
$qa = [...$owner, 'url'=>null, 'database'=>$s['DB_DATABASE'], 'username'=>$s['DB_USERNAME'], 'password'=>$s['DB_PASSWORD']];
config(['database.connections.receipt_install'=>$qa, 'database.connections.receipt_owner'=>[...$owner,'url'=>null,'database'=>'postgres']]);
DB::setDefaultConnection('receipt_install');
$db = DB::connection(); $admin = DB::connection('receipt_owner');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $s['DB_DATABASE'] || $identity->role !== $s['DB_USERNAME']) { throw new LogicException('Identity mismatch.'); }
$proofPath = $root.'/docs/proofs/receipt-block-installation.json';
if (file_exists($proofPath)) { throw new LogicException('Installation proof exists; inspect before repeating.'); }
$tables = array_column($db->select("select tablename from pg_tables where schemaname='public' order by tablename"),'tablename');
if (in_array('receipt_documents',$tables,true)) { throw new LogicException('Document table already exists.'); }
$fingerprint = function($connection,$tables) { $out=[]; foreach($tables as $table) { $rows=$connection->select('select row_to_json(t)::text as row from "'.str_replace('"','""',$table).'" t order by row_to_json(t)::text'); $out[$table]=hash('sha256',json_encode(array_column($rows,'row'),JSON_THROW_ON_ERROR)); } return $out; };
$pg = function($binary,$args,$connection) { $p=new Process(['C:/Program Files/PostgreSQL/17/bin/'.$binary.'.exe',...$args],null,['PGHOST'=>$connection['host'],'PGPORT'=>(string)$connection['port'],'PGUSER'=>$connection['username'],'PGPASSWORD'=>$connection['password']],timeout:120); $p->run(); if(!$p->isSuccessful()) { throw new RuntimeException('Backup/restore failed.'); } };
$restore='compras_pilot_restore_'.bin2hex(random_bytes(6)); $created=false;
try {
$db->beginTransaction(); $db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ');
$baseline=$fingerprint($db,$tables);
$directory='C:/laragon/data/sgf-tempo/backups/compras-receipt-documents-'.gmdate('Ymd-His').'-'.bin2hex(random_bytes(3));
if(!mkdir($directory,0700,true)) { throw new RuntimeException('Backup directory unavailable.'); }
$dump=$directory.'/before.dump';
$snapshot=$db->selectOne('select pg_export_snapshot() as snapshot')->snapshot;
$pg('pg_dump',['--format=custom','--snapshot='.$snapshot,'--file='.$dump,'--dbname='.$qa['database']],$qa);
$db->commit();
$admin->statement('CREATE DATABASE "'.$restore.'"'); $created=true;
$pg('pg_restore',['--no-owner','--no-privileges','--exit-on-error','--dbname='.$restore,$dump],$owner);
config(['database.connections.receipt_restore'=>[...$owner,'url'=>null,'database'=>$restore]]);
if($fingerprint(DB::connection('receipt_restore'),$tables)!==$baseline) { throw new LogicException('Restored backup differs.'); }
$disk=Storage::disk('receipt_documents'); $probe='.installation-'.bin2hex(random_bytes(8));
try { $disk->put($probe,'private-storage-probe'); if($disk->get($probe)!=='private-storage-probe') { throw new RuntimeException('Storage unavailable.'); } } finally { $disk->delete($probe); }
$migration='database/migrations/2026_11_03_000002_create_receipt_documents.php';
$db->transaction(function() use($db,$tables,$baseline,$fingerprint,$migration) {
foreach($tables as $table) { $db->statement('LOCK TABLE "'.str_replace('"','""',$table).'" IN SHARE MODE'); }
if($fingerprint($db,$tables)!==$baseline) { throw new LogicException('Pilot changed after backup; abort.'); }
if(Artisan::call('migrate',['--database'=>'receipt_install','--path'=>$migration,'--force'=>true])!==0) { throw new RuntimeException('Target migration failed.'); }
$protected=array_values(array_diff($tables,['migrations']));
if($fingerprint($db,$protected)!==array_intersect_key($baseline,array_flip($protected))) { throw new LogicException('Business data changed.'); }
if($db->table('receipt_documents')->count()!==0 || $db->table('migrations')->where('migration','2026_11_03_000001_add_two_factor_columns_to_users')->exists()) { throw new LogicException('Unexpected installation state.'); }
});
$proof=['checked_at'=>gmdate('c'),'environment'=>'http://127.0.0.1:8005','result'=>'passed','authorization'=>'User explicitly authorized receipt document block installation','migration'=>$migration,'backup'=>$dump,'backup_sha256'=>hash_file('sha256',$dump),'restored_tables_checked'=>count($tables),'protected_tables_checked'=>count($tables)-1,'business_data_unchanged'=>true,'documents_created'=>0,'mfa_enabled'=>false,'restore_database_removed'=>false];
} finally {
if($db->transactionLevel()>0) { $db->rollBack(); }
DB::purge('receipt_restore');
if($created) { $admin->statement('DROP DATABASE "'.$restore.'" WITH (FORCE)'); }
$owner = DB::connection('pgsql')->getConfig();
unset($owner['name']);
if ($owner['host'] !== '127.0.0.1') {
throw new LogicException('Local server required.');
}
$proof['restore_database_removed']=true;
file_put_contents($proofPath,json_encode($proof,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES).PHP_EOL);
$qa = [...$owner, 'url' => null, 'database' => $s['DB_DATABASE'], 'username' => $s['DB_USERNAME'], 'password' => $s['DB_PASSWORD']];
config(['database.connections.receipt_install' => $qa, 'database.connections.receipt_owner' => [...$owner, 'url' => null, 'database' => 'postgres']]);
DB::setDefaultConnection('receipt_install');
$db = DB::connection();
$admin = DB::connection('receipt_owner');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $s['DB_DATABASE'] || $identity->role !== $s['DB_USERNAME']) {
throw new LogicException('Identity mismatch.');
}
$proofPath = $root.'/docs/proofs/receipt-block-installation.json';
if (file_exists($proofPath)) {
throw new LogicException('Installation proof exists; inspect before repeating.');
}
$tables = array_column($db->select("select tablename from pg_tables where schemaname='public' order by tablename"), 'tablename');
if (in_array('receipt_documents', $tables, true)) {
throw new LogicException('Document table already exists.');
}
$fingerprint = function ($connection, $tables) {
$out = [];
foreach ($tables as $table) {
$rows = $connection->select('select row_to_json(t)::text as row from "'.str_replace('"', '""', $table).'" t order by row_to_json(t)::text');
$out[$table] = hash('sha256', json_encode(array_column($rows, 'row'), JSON_THROW_ON_ERROR));
}
return $out;
};
$pg = function ($binary, $args, $connection) {
$p = new Process(['C:/Program Files/PostgreSQL/17/bin/'.$binary.'.exe', ...$args], null, ['PGHOST' => $connection['host'], 'PGPORT' => (string) $connection['port'], 'PGUSER' => $connection['username'], 'PGPASSWORD' => $connection['password']], timeout: 120);
$p->run();
if (! $p->isSuccessful()) {
throw new RuntimeException('Backup/restore failed.');
}
};
$restore = 'compras_pilot_restore_'.bin2hex(random_bytes(6));
$created = false;
try {
$db->beginTransaction();
$db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ');
$baseline = $fingerprint($db, $tables);
$directory = 'C:/laragon/data/sgf-tempo/backups/compras-receipt-documents-'.gmdate('Ymd-His').'-'.bin2hex(random_bytes(3));
if (! mkdir($directory, 0700, true)) {
throw new RuntimeException('Backup directory unavailable.');
}
$dump = $directory.'/before.dump';
$snapshot = $db->selectOne('select pg_export_snapshot() as snapshot')->snapshot;
$pg('pg_dump', ['--format=custom', '--snapshot='.$snapshot, '--file='.$dump, '--dbname='.$qa['database']], $qa);
$db->commit();
$admin->statement('CREATE DATABASE "'.$restore.'"');
$created = true;
$pg('pg_restore', ['--no-owner', '--no-privileges', '--exit-on-error', '--dbname='.$restore, $dump], $owner);
config(['database.connections.receipt_restore' => [...$owner, 'url' => null, 'database' => $restore]]);
if ($fingerprint(DB::connection('receipt_restore'), $tables) !== $baseline) {
throw new LogicException('Restored backup differs.');
}
$disk = Storage::disk('receipt_documents');
$probe = '.installation-'.bin2hex(random_bytes(8));
try {
$disk->put($probe, 'private-storage-probe');
if ($disk->get($probe) !== 'private-storage-probe') {
throw new RuntimeException('Storage unavailable.');
}
} finally {
$disk->delete($probe);
}
$migration = 'database/migrations/2026_11_03_000002_create_receipt_documents.php';
$db->transaction(function () use ($db, $tables, $baseline, $fingerprint, $migration) {
foreach ($tables as $table) {
$db->statement('LOCK TABLE "'.str_replace('"', '""', $table).'" IN SHARE MODE');
}
if ($fingerprint($db, $tables) !== $baseline) {
throw new LogicException('Pilot changed after backup; abort.');
}
if (Artisan::call('migrate', ['--database' => 'receipt_install', '--path' => $migration, '--force' => true]) !== 0) {
throw new RuntimeException('Target migration failed.');
}
$protected = array_values(array_diff($tables, ['migrations']));
if ($fingerprint($db, $protected) !== array_intersect_key($baseline, array_flip($protected))) {
throw new LogicException('Business data changed.');
}
if ($db->table('receipt_documents')->count() !== 0 || $db->table('migrations')->where('migration', '2026_11_03_000001_add_two_factor_columns_to_users')->exists()) {
throw new LogicException('Unexpected installation state.');
}
});
$proof = ['checked_at' => gmdate('c'), 'environment' => 'http://127.0.0.1:8005', 'result' => 'passed', 'authorization' => 'User explicitly authorized receipt document block installation', 'migration' => $migration, 'backup' => $dump, 'backup_sha256' => hash_file('sha256', $dump), 'restored_tables_checked' => count($tables), 'protected_tables_checked' => count($tables) - 1, 'business_data_unchanged' => true, 'documents_created' => 0, 'mfa_enabled' => false, 'restore_database_removed' => false];
} finally {
if ($db->transactionLevel() > 0) {
$db->rollBack();
}
DB::purge('receipt_restore');
if ($created) {
$admin->statement('DROP DATABASE "'.$restore.'" WITH (FORCE)');
}
}
$proof['restore_database_removed'] = true;
file_put_contents($proofPath, json_encode($proof, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'Receipt documents installed; backup restored and business data preserved.'.PHP_EOL;
+1 -1
View File
@@ -18,7 +18,7 @@ await new Function('fs','assert','return (async()=>{'+common+`
records.push({role,status:result.status,mfaDisabled:true});
}
await fs.writeFile('docs/proofs/mfa-management-http.json',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',records,
enrollment_commands:false,password_changes:false,accounts_or_grants_changed:false,pilot_migration_applied:false,sgf_changed:false,visual_review:false,
enrollment_commands:false,password_changes:false,accounts_or_grants_changed:false,migration_status_not_inferred_from_http:true,sgf_changed:false,visual_review:false,
coverage:'Pilot remains disabled; enabled native management flows tested in disposable databases.'},null,2));
console.log('Interface de segurança conferida; adesão MFA do piloto permanece desactivada.');
`+'})()')(fs,assert);
+18
View File
@@ -0,0 +1,18 @@
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const source = await fs.readFile('scripts/supplier-evaluation-check.mjs', 'utf8');
const common = source.slice(source.indexOf('const base ='), source.indexOf('const author ='));
await new Function('fs', 'assert', 'return (async()=>{' + common + `
const records=[];
for(const role of ['admin','warehouse','procurement','finance']) {
const viewer=client(); await viewer.enter(role);
assert.equal((await viewer.request('/contexto','POST',{area:'procurement',option:'procurement.internal'})).status,302);
const stock=await viewer.request('/stock'); assert.equal(stock.status,200); assert.equal(stock.page.props.geographyEnabled,false);
const equipment=await viewer.request('/equipamentos'); assert.equal(equipment.status,200); assert.equal(equipment.page.props.geographyEnabled,false);
const catalogue=await viewer.request('/api/divisao-administrativa'); assert.equal(catalogue.status,200); assert.equal(catalogue.page.data.length,11);
if(role!=='warehouse') { const suppliers=await viewer.request('/fornecedores'); assert.equal(suppliers.status,200); assert.equal(suppliers.page.props.geographyEnabled,true); }
records.push({role,stockStatus:200,equipmentStatus:200,newControlsHidden:true,existingCatalogueAvailable:true});
}
await fs.writeFile('docs/proofs/operational-geography-http.json',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',records,business_commands:false,classification_commands:false,approval_changes:false,mfa_activation:false,visual_review:false},null,2));
console.log('Operational controls remain hidden pending schema approval; current geography catalogue remains available.');
` + '})()')(fs, assert);
@@ -0,0 +1,47 @@
<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
$settings = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($settings['APP_ENV'] ?? '') !== 'payable-testing' || ($settings['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($settings['HOST_ROOT'] ?? '') !== realpath($root)
|| ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $settings['DB_DATABASE'] ?? '', $matches) || $settings['DB_USERNAME'] !== 'payable_qa_'.$matches[1]) {
throw new LogicException('Wrong pilot destination.');
}
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$base = DB::connection('pgsql')->getConfig();
unset($base['name']);
config(['database.connections.geography_pilot_read' => [...$base, 'url' => null, 'host' => $settings['DB_HOST'], 'port' => $settings['DB_PORT'],
'database' => $settings['DB_DATABASE'], 'username' => $settings['DB_USERNAME'], 'password' => $settings['DB_PASSWORD']]]);
$db = DB::connection('geography_pilot_read');
$result = $db->transaction(function () use ($db, $settings) {
$db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $settings['DB_DATABASE'] || $identity->role !== $settings['DB_USERNAME']) {
throw new LogicException('Identity mismatch.');
}
$schema = Schema::connection('geography_pilot_read');
return ['checked_at' => gmdate('c'), 'environment' => 'http://127.0.0.1:8005', 'result' => 'passed',
'warehouse_column_installed' => $schema->hasColumn('warehouses', 'geography_reference'),
'equipment_column_installed' => $schema->hasColumn('equipment', 'geography_reference'),
'operational_flag' => filter_var($settings['SGC_OPERATIONAL_GEOGRAPHY_ENABLED'] ?? false, FILTER_VALIDATE_BOOLEAN),
'operational_migration_applied' => $db->table('migrations')->where('migration', '2026_11_03_000005_add_operational_geography_references')->exists(),
'supplier_column_installed' => $schema->hasColumn('suppliers', 'geography_reference'),
'company_column_installed' => $schema->hasColumn('tenants', 'geography_reference'),
'migration_applied' => $db->table('migrations')->where('migration', '2026_11_03_000004_add_administrative_geography_references')->exists(),
'mfa_accounts_enrolled' => $db->table('users')->where(fn ($q) => $q->whereNotNull('two_factor_secret')->orWhereNotNull('two_factor_recovery_codes')->orWhereNotNull('two_factor_confirmed_at'))->count(),
'access_version' => (int) $db->table('organization_access')->where('tenant_id', 1)->value('version'),
'business_commands' => false, 'geography_flag' => filter_var($settings['SGC_GEOGRAPHY_ENABLED'] ?? false, FILTER_VALIDATE_BOOLEAN),
'classified_suppliers' => $db->table('suppliers')->whereNotNull('geography_reference')->count(),
'classified_companies' => $db->table('tenants')->whereNotNull('geography_reference')->count()];
});
if (! $result['migration_applied'] || ! $result['geography_flag'] || $result['warehouse_column_installed'] || $result['equipment_column_installed'] || $result['operational_migration_applied'] || $result['operational_flag'] || $result['mfa_accounts_enrolled']) {
throw new LogicException('Pilot differs from the expected operational geography preparation scope.');
}
file_put_contents($root.'/docs/proofs/operational-geography-pilot.json', json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'Geography pilot inspected read-only: operational columns absent; existing company/supplier selection preserved; no business commands.'.PHP_EOL;
+23
View File
@@ -0,0 +1,23 @@
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const source = await fs.readFile('scripts/supplier-evaluation-check.mjs', 'utf8');
const common = source.slice(source.indexOf('const base ='), source.indexOf('const author ='));
await new Function('fs', 'assert', 'return (async()=>{' + common + `
const records=[];
for(const role of ['admin','procurement','finance']) {
const viewer=client(); await viewer.enter(role);
assert.equal((await viewer.request('/contexto','POST',{area:'procurement',option:'procurement.internal'})).status,302);
assert.equal((await viewer.request('/ordens/cancelamentos','GET',undefined,false)).status,503);
const orders=await viewer.request('/ordens'); assert.equal(orders.status,200);
let checked=0;
for(const order of orders.page.props.orders.data.slice(0,1)) {
const detail=await viewer.request('/ordens/'+order.id); assert.equal(detail.status,200);
assert.equal(detail.page.props.orderCancellation.enabled,false);
assert.equal(detail.page.props.orderCancellation.canRequest,false);
assert.equal(detail.page.props.orderCancellationAvailable,false); checked++;
}
records.push({role,disabledStatus:503,ordersChecked:checked});
}
await fs.writeFile('docs/proofs/issued-order-cancellation-http.json',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',records,business_commands:false,policy_commands:false,cancellation_commands:false,visual_review:false},null,2));
console.log('Circuito desligado no piloto; ordens existentes consultadas sem comandos de cancelamento.');
` + '})()')(fs, assert);
@@ -0,0 +1,42 @@
<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
$settings = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($settings['APP_ENV'] ?? '') !== 'payable-testing' || ($settings['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($settings['HOST_ROOT'] ?? '') !== realpath($root)
|| ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $settings['DB_DATABASE'] ?? '', $matches) || $settings['DB_USERNAME'] !== 'payable_qa_'.$matches[1]) {
throw new LogicException('Wrong pilot destination.');
}
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$base = DB::connection('pgsql')->getConfig();
unset($base['name']);
config(['database.connections.cancel_pilot_read' => [...$base, 'url' => null, 'host' => $settings['DB_HOST'], 'port' => $settings['DB_PORT'],
'database' => $settings['DB_DATABASE'], 'username' => $settings['DB_USERNAME'], 'password' => $settings['DB_PASSWORD']]]);
$db = DB::connection('cancel_pilot_read');
$result = $db->transaction(function () use ($db, $settings) {
$db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $settings['DB_DATABASE'] || $identity->role !== $settings['DB_USERNAME']) {
throw new LogicException('Identity mismatch.');
}
$schema = Schema::connection('cancel_pilot_read');
$installed = $schema->hasTable('order_cancellations');
return ['checked_at' => gmdate('c'), 'environment' => 'http://127.0.0.1:8005', 'result' => 'passed',
'schema_installed' => $installed, 'migration_applied' => $db->table('migrations')->where('migration', '2026_11_03_000003_create_order_cancellations')->exists(),
'cancellations' => $installed ? $db->table('order_cancellations')->count() : 0,
'policies' => $schema->hasTable('order_cancellation_policies') ? $db->table('order_cancellation_policies')->count() : 0,
'mfa_accounts_enrolled' => $db->table('users')->where(fn ($q) => $q->whereNotNull('two_factor_secret')->orWhereNotNull('two_factor_recovery_codes')->orWhereNotNull('two_factor_confirmed_at'))->count(),
'audit_permission_profiles' => $db->table('organization_profiles')->whereJsonContains('permissions', 'audit_metadata_read')->count(),
'access_version' => (int) $db->table('organization_access')->where('tenant_id', 1)->value('version'), 'business_commands' => false];
});
if ($result['schema_installed'] || $result['migration_applied'] || $result['cancellations'] || $result['policies'] || $result['mfa_accounts_enrolled'] || $result['audit_permission_profiles']) {
throw new LogicException('Pilot state differs from the authorized disabled scope.');
}
file_put_contents($root.'/docs/proofs/issued-order-cancellation-pilot.json', json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'Pilot inspected read-only: circuit uninstalled and disabled; no policies, cancellations or MFA enrollments.'.PHP_EOL;
+21
View File
@@ -0,0 +1,21 @@
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const source = await fs.readFile('scripts/supplier-evaluation-check.mjs', 'utf8');
const common = source.slice(source.indexOf('const base ='), source.indexOf('const author ='));
await new Function('fs', 'assert', 'return (async()=>{' + common + `
const viewer=client(); await viewer.enter('admin');
assert.equal((await viewer.request('/contexto','POST',{area:'people',option:'people.internal'})).status,302);
const index=await viewer.request('/pessoas'); assert.equal(index.status,200);
let dossiersChecked=0;
for(const process of index.page.props.processes.data.slice(0,2)) {
const dossier=await viewer.request('/pessoas/'+process.id+'/dossier.json','GET',undefined,false);
assert.equal(dossier.status,200);
assert.equal(dossier.page.schema,'sgc.people.process-dossier.v1');
assert.equal(dossier.page.effect,'preparation_only');
assert.equal(dossier.page.process.tenant_id,undefined);
assert.equal(dossier.page.process.creation_hash,undefined);
dossiersChecked++;
}
await fs.writeFile('docs/proofs/people-dossier-http.json',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',dossiersChecked,business_commands:false,visual_review:false,coverage:'Existing visible processes only; service and staff journeys exercised in disposable databases.'},null,2));
console.log('Consulta de Pessoas conferida; sem decisões ou novos registos.');
` + '})()')(fs, assert);
+130
View File
@@ -0,0 +1,130 @@
<?php
use App\Models\User;
use App\Services\OrganizationAccess;
use App\Services\OrganizationConfiguration;
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Symfony\Component\Process\Process;
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
if (! in_array('--prepare-audit-access', $argv, true)) {
throw new LogicException('Explicit preparation flag required.');
}
$s = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($s['APP_ENV'] ?? '') !== 'payable-testing' || ($s['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($s['HOST_ROOT'] ?? '') !== realpath($root) || ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $s['DB_DATABASE'] ?? '', $m) || $s['DB_USERNAME'] !== 'payable_qa_'.$m[1]) {
throw new LogicException('Wrong pilot destination.');
}
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$owner = DB::connection('pgsql')->getConfig();
unset($owner['name']);
if ($owner['host'] !== '127.0.0.1') {
throw new LogicException('Local server required.');
}
$qa = [...$owner, 'url' => null, 'database' => $s['DB_DATABASE'], 'username' => $s['DB_USERNAME'], 'password' => $s['DB_PASSWORD']];
config(['database.connections.receipt_install' => $qa, 'database.connections.receipt_owner' => [...$owner, 'url' => null, 'database' => 'postgres']]);
DB::setDefaultConnection('receipt_install');
$db = DB::connection();
$admin = DB::connection('receipt_owner');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $s['DB_DATABASE'] || $identity->role !== $s['DB_USERNAME']) {
throw new LogicException('Identity mismatch.');
}
$fingerprint = function ($connection, $tables) {
$out = [];
foreach ($tables as $table) {
$rows = $connection->select('select row_to_json(t)::text as row from "'.str_replace('"', '""', $table).'" t order by row_to_json(t)::text');
$out[$table] = hash('sha256', json_encode(array_column($rows, 'row'), JSON_THROW_ON_ERROR));
}
return $out;
};
$pg = function ($binary, $args, $connection) {
$p = new Process(['C:/Program Files/PostgreSQL/17/bin/'.$binary.'.exe', ...$args], null, ['PGHOST' => $connection['host'], 'PGPORT' => (string) $connection['port'], 'PGUSER' => $connection['username'], 'PGPASSWORD' => $connection['password']], timeout: 120);
$p->run();
if (! $p->isSuccessful()) {
throw new RuntimeException('Backup/restore failed.');
}
};
$tables = array_column($db->select("select tablename from pg_tables where schemaname='public' order by tablename"), 'tablename');
$restore = 'compras_pilot_restore_'.bin2hex(random_bytes(6));
$created = false;
try {
$db->beginTransaction();
$db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ');
$baseline = $fingerprint($db, $tables);
$directory = 'C:/laragon/data/sgf-tempo/backups/compras-audit-access-preparation-'.gmdate('Ymd-His').'-'.bin2hex(random_bytes(3));
if (! mkdir($directory, 0700, true)) {
throw new RuntimeException('Backup unavailable.');
}
$dump = $directory.'/before.dump';
$snapshot = $db->selectOne('select pg_export_snapshot() as snapshot')->snapshot;
$pg('pg_dump', ['--format=custom', '--snapshot='.$snapshot, '--file='.$dump, '--dbname='.$qa['database']], $qa);
$db->commit();
$admin->statement('CREATE DATABASE "'.$restore.'"');
$created = true;
$pg('pg_restore', ['--no-owner', '--no-privileges', '--exit-on-error', '--dbname='.$restore, $dump], $owner);
config(['database.connections.receipt_restore' => [...$owner, 'url' => null, 'database' => $restore], 'work_context.composition' => 'sgc']);
$restored = DB::connection('receipt_restore');
if ($fingerprint($restored, $tables) !== $baseline) {
throw new LogicException('Restored backup differs.');
}
DB::setDefaultConnection('receipt_restore');
$app->detectEnvironment(fn () => 'payable-testing');
$request = Request::create('http://127.0.0.1:8005/administracao/parametrizacao', 'GET', server: ['REMOTE_ADDR' => '127.0.0.1']);
$request->setLaravelSession($app['session']->driver('array'));
$app->instance('request', $request);
$actor = User::query()->findOrFail(6);
auth()->guard('web')->setUser($actor);
$request->setUserResolver(fn () => $actor);
$request->session()->put('work_context', ['key' => 'procurement.internal', 'user_id' => $actor->id, 'tenant_id' => $actor->tenant_id]);
$tenant = $actor->tenant_id;
$version = (int) $restored->table('organization_access')->where('tenant_id', $tenant)->value('version');
$beforePermissions = [];
$profiles = [];
foreach ([6, 8] as $id) {
$user = User::query()->where('tenant_id', $tenant)->findOrFail($id);
$beforePermissions[$id] = app(OrganizationAccess::class)->permissions($user, 'procurement.internal');
if (! in_array('admin', $beforePermissions[$id], true) || in_array('audit_metadata_read', $beforePermissions[$id], true)) {
throw new LogicException('Proposed administrators changed.');
}
$members = $restored->table('organization_memberships')->where('tenant_id', $tenant)->where('user_id', $id)->get();
foreach ($members as $m) {
if ($m->maintenance || $m->expires_at !== null) {
throw new LogicException('Membership conditions require a separate proposal.');
}
}$profiles[$id] = $members->pluck('profile_id')->all();
}
$flow = app(OrganizationConfiguration::class);
$flow->execute($actor, 'profile', ['version' => $version, 'name' => 'Auditoria de metadados — piloto sintético', 'permissions' => ['audit_metadata_read'], 'work_contexts' => ['procurement.internal'], 'reason' => 'Ensaio descartável da proposta de consulta de metadados.']);
$profile = (int) $restored->table('organization_profiles')->where('tenant_id', $tenant)->max('id');
foreach ([6, 8] as $index => $id) {
$flow->execute($actor, 'assign', ['version' => $version + 1 + $index, 'user_id' => $id, 'profile_ids' => [...$profiles[$id], $profile], 'maintenance' => false, 'expires_at' => null, 'reason' => 'Ensaio descartável: acrescentar só consulta de metadados, preservando competências.']);
$user = User::query()->findOrFail($id);
$after = app(OrganizationAccess::class)->permissions($user, 'procurement.internal');
$expected = [...$beforePermissions[$id], 'audit_metadata_read'];
sort($after);
sort($expected);
if ($after !== $expected) {
throw new LogicException('Unexpected permission change.');
}
}
$protected = array_values(array_diff($tables, ['organization_profiles', 'organization_memberships', 'organization_access', 'audit_logs']));
if ($fingerprint($restored, $protected) !== array_intersect_key($baseline, array_flip($protected))) {
throw new LogicException('Unexpected business changes.');
}
$result = ['checked_at' => gmdate('c'), 'result' => 'passed', 'environment' => 'http://127.0.0.1:8005', 'tenant_id' => $tenant, 'expected_access_version' => $version, 'proposed_access_version' => $version + 3, 'actors' => [6, 8], 'new_profile' => ['name' => 'Auditoria de metadados — piloto sintético', 'permissions' => ['audit_metadata_read'], 'work_contexts' => ['procurement.internal']], 'existing_profile_ids' => $profiles, 'existing_permissions_preserved' => true, 'backup' => $dump, 'backup_sha256' => hash_file('sha256', $dump), 'restored_tables_checked' => count($tables), 'protected_tables_checked' => count($protected), 'pilot_grants_changed' => false, 'pilot_mfa_enabled' => false, 'restore_database_removed' => false];
} finally {
if ($db->transactionLevel() > 0) {
$db->rollBack();
}DB::purge('receipt_restore');
if ($created) {
$admin->statement('DROP DATABASE "'.$restore.'" WITH (FORCE)');
}
}
$result['restore_database_removed'] = true;
file_put_contents($root.'/docs/proofs/audit-access-preparation.json',json_encode($result,JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'Audit access proposal rehearsed only in restored disposable backup; pilot grants unchanged.'.PHP_EOL;
+93
View File
@@ -0,0 +1,93 @@
"""Read-only XLSX extraction. No spreadsheet or pilot database is changed."""
import argparse
import collections
import hashlib
import json
from pathlib import Path
import xml.etree.ElementTree as ET
import zipfile
def prepare(source, destination):
content = Path(source).read_bytes()
digest = hashlib.sha256(content).hexdigest()
ns = {"m": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}
with zipfile.ZipFile(source) as archive:
strings = ["".join(t.text or "" for t in item.iter("{" + ns["m"] + "}t"))
for item in ET.fromstring(archive.read("xl/sharedStrings.xml"))]
xml = ET.fromstring(archive.read("xl/worksheets/sheet1.xml"))
parsed = []
for row in xml.findall("m:sheetData/m:row", ns):
cells = {}
for cell in row:
value = cell.find("m:v", ns)
value = value.text if value is not None else "".join(cell.itertext())
cells["".join(filter(str.isalpha, cell.get("r")))] = strings[int(value)] if cell.get("t") == "s" else value
if any(cells.values()):
parsed.append((int(row.get("r")), cells))
expected = ["ID", "Provincia", "Distrito", "Posto_Administrativo", "Localidade", "Bairro_Urbano", "Aldeia_Quarteirao", "Designacao"]
if [parsed[0][1].get(c, "") for c in "ABCDEFGH"] != expected:
raise ValueError("Unexpected source columns; import stopped")
records = []
by_path = collections.defaultdict(list)
ids = set()
for row, cells in parsed[1:]:
raw = {key: cells.get(col, "") for col, key in zip("ABCDEFGH", expected)}
identifier = raw["ID"]
if not identifier.isdecimal() or identifier in ids:
raise ValueError("Missing or duplicate source ID; import stopped")
ids.add(identifier)
codes = [cells.get(c, "").strip() for c in "BCDEFG"]
positions = [i for i, code in enumerate(codes) if code]
level = max(positions) + 1 if positions else 0
issues = []
if not raw["Designacao"].strip():
issues.append("blank_designation")
if not level or positions != list(range(level)):
issues.append("incomplete_code_path")
record = {"id": identifier, "source_row": row, "raw": raw, "codes": codes,
"level": level, "name": raw["Designacao"], "parent_id": None, "issues": issues}
records.append(record)
by_path[tuple(codes)].append(record)
for record in records:
if len(by_path[tuple(record["codes"])]) > 1:
record["issues"].append("duplicate_code_path")
if record["level"] > 1:
parent = record["codes"].copy()
parent[record["level"] - 1] = ""
candidates = by_path.get(tuple(parent), [])
if len(candidates) == 1:
record["parent_id"] = candidates[0]["id"]
else:
record["issues"].append("missing_parent" if not candidates else "ambiguous_parent")
by_id = {r["id"]: r for r in records}
for record in sorted(records, key=lambda r: r["level"]):
parent = by_id.get(record["parent_id"])
if parent and not parent["selectable"]:
record["issues"].append("ancestor_requires_review")
record["selectable"] = not record["issues"]
manifest = {"schema_version": 1, "country": "MZ", "source_file": Path(source).name,
"source_sha256": digest, "source_sheet": "Sheet1", "edition": None,
"authority": "INE, conforme indicação do proprietário; edição não verificada",
"columns": expected, "records": len(records),
"selectable": sum(r["selectable"] for r in records),
"levels": dict(collections.Counter(r["level"] for r in records)),
"issues": dict(collections.Counter(issue for r in records for issue in r["issues"])),
"duplicate_code_groups": sum(len(v) > 1 for v in by_path.values())}
result = {"manifest": manifest, "records": records}
destination = Path(destination)
if destination.exists():
previous = json.loads(destination.read_text(encoding="utf-8"))
if previous["manifest"]["source_sha256"] != digest:
raise ValueError("Preserve previous catalogue: use a new destination for a new source revision")
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(json.dumps(result, ensure_ascii=False, separators=(",", ":")) + "\n", encoding="utf-8")
print(json.dumps(manifest, ensure_ascii=False, indent=2))
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("source")
parser.add_argument("destination")
args = parser.parse_args()
prepare(args.source, args.destination)
+103
View File
@@ -0,0 +1,103 @@
<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Symfony\Component\Process\Process;
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
if (! in_array('--prepare-issued-order-schema', $argv, true)) {
throw new LogicException('Explicit preparation flag required.');
}
$s = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($s['APP_ENV'] ?? '') !== 'payable-testing' || ($s['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($s['HOST_ROOT'] ?? '') !== realpath($root) || ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $s['DB_DATABASE'] ?? '', $m) || $s['DB_USERNAME'] !== 'payable_qa_'.$m[1]) {
throw new LogicException('Wrong pilot destination.');
}
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$owner = DB::connection('pgsql')->getConfig();
unset($owner['name']);
if ($owner['host'] !== '127.0.0.1') {
throw new LogicException('Local server required.');
}
$qa = [...$owner, 'url' => null, 'database' => $s['DB_DATABASE'], 'username' => $s['DB_USERNAME'], 'password' => $s['DB_PASSWORD']];
config(['database.connections.receipt_install' => $qa, 'database.connections.receipt_owner' => [...$owner, 'url' => null, 'database' => 'postgres']]);
DB::setDefaultConnection('receipt_install');
$db = DB::connection();
$admin = DB::connection('receipt_owner');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $s['DB_DATABASE'] || $identity->role !== $s['DB_USERNAME']) {
throw new LogicException('Identity mismatch.');
}
$fingerprint = function ($connection, $tables) {
$out = [];
foreach ($tables as $table) {
$rows = $connection->select('select row_to_json(t)::text as row from "'.str_replace('"', '""', $table).'" t order by row_to_json(t)::text');
$out[$table] = hash('sha256', json_encode(array_column($rows, 'row'), JSON_THROW_ON_ERROR));
}
return $out;
};
$pg = function ($binary, $args, $connection) {
$p = new Process(['C:/Program Files/PostgreSQL/17/bin/'.$binary.'.exe', ...$args], null, ['PGHOST' => $connection['host'], 'PGPORT' => (string) $connection['port'], 'PGUSER' => $connection['username'], 'PGPASSWORD' => $connection['password']], timeout: 120);
$p->run();
if (! $p->isSuccessful()) {
throw new RuntimeException('Backup/restore failed.');
}
};
$tables = array_column($db->select("select tablename from pg_tables where schemaname='public' order by tablename"), 'tablename');
$migration = 'database/migrations/2026_11_03_000003_create_order_cancellations.php';
$newTables = ['order_cancellation_policies', 'order_cancellation_policy_reviews', 'order_cancellations'];
if (config('order_cancellation.enabled') || array_intersect($tables, $newTables)) {
throw new LogicException('Circuit must remain disabled and uninstalled in the pilot.');
}
$restore = 'compras_pilot_restore_'.bin2hex(random_bytes(6));
$created = false;
try {
$db->beginTransaction();
$db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ');
$baseline = $fingerprint($db, $tables);
$directory = 'C:/laragon/data/sgf-tempo/backups/compras-issued-order-schema-'.gmdate('Ymd-His').'-'.bin2hex(random_bytes(3));
if (! mkdir($directory, 0700, true)) {
throw new RuntimeException('Backup unavailable.');
}
$dump = $directory.'/before.dump';
$snapshot = $db->selectOne('select pg_export_snapshot() as snapshot')->snapshot;
$pg('pg_dump', ['--format=custom', '--snapshot='.$snapshot, '--file='.$dump, '--dbname='.$qa['database']], $qa);
$db->commit();
$admin->statement('CREATE DATABASE "'.$restore.'"');
$created = true;
$pg('pg_restore', ['--no-owner', '--no-privileges', '--exit-on-error', '--dbname='.$restore, $dump], $owner);
config(['database.connections.receipt_restore' => [...$owner, 'url' => null, 'database' => $restore]]);
$restored = DB::connection('receipt_restore');
if ($fingerprint($restored, $tables) !== $baseline) {
throw new LogicException('Restored backup differs.');
}
$migrationCount = $restored->table('migrations')->count();
if (Artisan::call('migrate', ['--database' => 'receipt_restore', '--path' => $migration, '--force' => true]) !== 0) {
throw new RuntimeException('Disposable migration failed.');
}
$protected = array_values(array_diff($tables, ['migrations']));
if ($fingerprint($restored, $protected) !== array_intersect_key($baseline, array_flip($protected)) || $restored->table('migrations')->count() !== $migrationCount + 1) {
throw new LogicException('Unexpected existing data changes.');
}
foreach ($newTables as $table) {
if ($restored->table($table)->count() !== 0) {
throw new LogicException('New tables must remain empty.');
}
}
$result = ['checked_at' => gmdate('c'), 'result' => 'passed', 'environment' => 'http://127.0.0.1:8005', 'scope' => 'empty_schema_only_no_activation', 'migration' => $migration, 'migration_sha256' => hash_file('sha256', $root.'/'.$migration),
'new_empty_tables' => $newTables, 'backup' => $dump, 'backup_sha256' => hash_file('sha256', $dump), 'restored_tables_checked' => count($tables), 'protected_tables_checked' => count($protected),
'pilot_migration_applied' => false, 'pilot_configuration_changed' => false, 'policy_publication' => false, 'cancellation_commands' => false, 'mfa_enabled' => false, 'restore_database_removed' => false];
} finally {
if ($db->transactionLevel() > 0) {
$db->rollBack();
}DB::purge('receipt_restore');
if ($created) {
$admin->statement('DROP DATABASE "'.$restore.'" WITH (FORCE)');
}
}
$result['restore_database_removed'] = true;
file_put_contents($root.'/docs/proofs/issued-order-schema-preparation.json', json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'Empty cancellation schema rehearsed only in restored disposable backup; pilot unchanged.'.PHP_EOL;
+111
View File
@@ -0,0 +1,111 @@
<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Symfony\Component\Process\Process;
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
if (! in_array('--prepare', $argv, true)) {
throw new LogicException('Explicit preparation flag required.');
}
$s = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($s['APP_ENV'] ?? '') !== 'payable-testing' || ($s['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($s['HOST_ROOT'] ?? '') !== realpath($root) || ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $s['DB_DATABASE'] ?? '', $m) || $s['DB_USERNAME'] !== 'payable_qa_'.$m[1]) {
throw new LogicException('Wrong pilot destination.');
}
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$owner = DB::connection('pgsql')->getConfig();
unset($owner['name']);
if ($owner['host'] !== '127.0.0.1') {
throw new LogicException('Local server required.');
}
$qa = [...$owner, 'url' => null, 'database' => $s['DB_DATABASE'], 'username' => $s['DB_USERNAME'], 'password' => $s['DB_PASSWORD']];
config(['database.connections.receipt_install' => $qa, 'database.connections.receipt_owner' => [...$owner, 'url' => null, 'database' => 'postgres']]);
DB::setDefaultConnection('receipt_install');
$db = DB::connection();
$admin = DB::connection('receipt_owner');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $s['DB_DATABASE'] || $identity->role !== $s['DB_USERNAME']) {
throw new LogicException('Identity mismatch.');
}
$fingerprint = function ($connection, $tables) {
$out = [];
foreach ($tables as $table) {
$rows = $connection->select('select row_to_json(t)::text as row from "'.str_replace('"', '""', $table).'" t order by row_to_json(t)::text');
$out[$table] = hash('sha256', json_encode(array_column($rows, 'row'), JSON_THROW_ON_ERROR));
}
return $out;
};
$pg = function ($binary, $args, $connection) {
$p = new Process(['C:/Program Files/PostgreSQL/17/bin/'.$binary.'.exe', ...$args], null, ['PGHOST' => $connection['host'], 'PGPORT' => (string) $connection['port'], 'PGUSER' => $connection['username'], 'PGPASSWORD' => $connection['password']], timeout: 120);
$p->run();
if (! $p->isSuccessful()) {
throw new RuntimeException('Backup/restore failed.');
}
};
$tables = array_column($db->select("select tablename from pg_tables where schemaname='public' order by tablename"), 'tablename');
$migration = 'database/migrations/2026_11_03_000001_add_two_factor_columns_to_users.php';
foreach (['two_factor_secret', 'two_factor_recovery_codes', 'two_factor_confirmed_at'] as $column) {
if (Schema::connection('receipt_install')->hasColumn('users', $column)) {
throw new LogicException('MFA schema already exists; inspect before repeating.');
}
}
$restore = 'compras_pilot_restore_'.bin2hex(random_bytes(6));
$created = false;
try {
$db->beginTransaction();
$db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ');
$baseline = $fingerprint($db, $tables);
$directory = 'C:/laragon/data/sgf-tempo/backups/compras-mfa-preparation-'.gmdate('Ymd-His').'-'.bin2hex(random_bytes(3));
if (! mkdir($directory, 0700, true)) {
throw new RuntimeException('Backup unavailable.');
}
$dump = $directory.'/before.dump';
$snapshot = $db->selectOne('select pg_export_snapshot() as snapshot')->snapshot;
$pg('pg_dump', ['--format=custom', '--snapshot='.$snapshot, '--file='.$dump, '--dbname='.$qa['database']], $qa);
$db->commit();
$admin->statement('CREATE DATABASE "'.$restore.'"');
$created = true;
$pg('pg_restore', ['--no-owner', '--no-privileges', '--exit-on-error', '--dbname='.$restore, $dump], $owner);
config(['database.connections.receipt_restore' => [...$owner, 'url' => null, 'database' => $restore]]);
$restored = DB::connection('receipt_restore');
if ($fingerprint($restored, $tables) !== $baseline) {
throw new LogicException('Restored backup differs.');
}
$columns = Schema::connection('receipt_restore')->getColumnListing('users');
$userRows = function ($connection) use ($columns) {
$selected = implode(',', array_map(fn ($c) => '"'.str_replace('"', '""', $c).'"', $columns));
return $connection->select('select row_to_json(t)::text as row from (select '.$selected.' from users) t order by row_to_json(t)::text');
};
$beforeUsers = $userRows($restored);
$migrationCount = $restored->table('migrations')->count();
if (Artisan::call('migrate', ['--database' => 'receipt_restore', '--path' => $migration, '--force' => true]) !== 0) {
throw new RuntimeException('Disposable migration failed.');
}
$protected = array_values(array_diff($tables, ['users', 'migrations']));
if ($fingerprint($restored, $protected) !== array_intersect_key($baseline, array_flip($protected)) || $userRows($restored) != $beforeUsers || $restored->table('migrations')->count() !== $migrationCount + 1) {
throw new LogicException('Unexpected migration changes.');
}
foreach (['two_factor_secret', 'two_factor_recovery_codes', 'two_factor_confirmed_at'] as $column) {
if ($restored->table('users')->whereNotNull($column)->exists()) {
throw new LogicException('Unexpected enrollment data.');
}
}
$result = ['checked_at' => gmdate('c'), 'result' => 'passed', 'environment' => 'http://127.0.0.1:8005', 'scope' => 'prepare_schema_only_not_activation', 'migration' => $migration, 'migration_sha256' => hash_file('sha256', $root.'/'.$migration), 'backup' => $dump, 'backup_sha256' => hash_file('sha256', $dump), 'restored_tables_checked' => count($tables), 'protected_tables_checked' => count($protected), 'existing_user_columns_preserved' => true, 'existing_users' => $restored->table('users')->count(), 'enrollment_created' => false, 'pilot_migration_applied' => false, 'pilot_configuration_changed' => false, 'passwords_or_grants_changed' => false, 'restore_database_removed' => false];
} finally {
if ($db->transactionLevel() > 0) {
$db->rollBack();
}
DB::purge('receipt_restore');
if ($created) {
$admin->statement('DROP DATABASE "'.$restore.'" WITH (FORCE)');
}
}
$result['restore_database_removed'] = true;
file_put_contents($root.'/docs/proofs/mfa-pilot-schema-preparation.json', json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'MFA schema rehearsed only in restored disposable backup; pilot unchanged.'.PHP_EOL;
@@ -0,0 +1,131 @@
<?php
use Illuminate\Contracts\Console\Kernel;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Symfony\Component\Process\Process;
require dirname(__DIR__).'/vendor/autoload.php';
$root = dirname(__DIR__);
if (! in_array('--prepare-operational-geography', $argv, true)) {
throw new LogicException('Explicit read-only preparation flag required.');
}
$s = json_decode(file_get_contents('C:/laragon/data/sgf-tempo/secrets/payables-demo-compras.json'), true, 32, JSON_THROW_ON_ERROR);
if (($s['APP_ENV'] ?? '') !== 'payable-testing' || ($s['DB_HOST'] ?? '') !== '127.0.0.1' || realpath($s['HOST_ROOT'] ?? '') !== realpath($root) || ! preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D', $s['DB_DATABASE'] ?? '', $m) || $s['DB_USERNAME'] !== 'payable_qa_'.$m[1]) {
throw new LogicException('Wrong pilot destination.');
}
$app = require $root.'/bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
$owner = DB::connection('pgsql')->getConfig();
unset($owner['name']);
if ($owner['host'] !== '127.0.0.1') {
throw new LogicException('Local server required.');
}
$qa = [...$owner, 'url' => null, 'database' => $s['DB_DATABASE'], 'username' => $s['DB_USERNAME'], 'password' => $s['DB_PASSWORD']];
config(['database.connections.receipt_install' => $qa, 'database.connections.receipt_owner' => [...$owner, 'url' => null, 'database' => 'postgres']]);
DB::setDefaultConnection('receipt_install');
$db = DB::connection();
$admin = DB::connection('receipt_owner');
$identity = $db->selectOne('select current_database() as db, current_user as role');
if ($identity->db !== $s['DB_DATABASE'] || $identity->role !== $s['DB_USERNAME']) {
throw new LogicException('Identity mismatch.');
}
$fingerprint = function ($connection, $tables) {
$out = [];
foreach ($tables as $table) {
$rows = $connection->select('select row_to_json(t)::text as row from "'.str_replace('"', '""', $table).'" t order by row_to_json(t)::text');
$out[$table] = hash('sha256', json_encode(array_column($rows, 'row'), JSON_THROW_ON_ERROR));
}
return $out;
};
$pg = function ($binary, $args, $connection) {
$p = new Process(['C:/Program Files/PostgreSQL/17/bin/'.$binary.'.exe', ...$args], null, ['PGHOST' => $connection['host'], 'PGPORT' => (string) $connection['port'], 'PGUSER' => $connection['username'], 'PGPASSWORD' => $connection['password']], timeout: 120);
$p->run();
if (! $p->isSuccessful()) {
throw new RuntimeException('Backup/restore failed.');
}
};
$tables = array_column($db->select("select tablename from pg_tables where schemaname='public' order by tablename"), 'tablename');
$migration = 'database/migrations/2026_11_03_000005_add_operational_geography_references.php';
if (! filter_var($s['SGC_GEOGRAPHY_ENABLED'] ?? false, FILTER_VALIDATE_BOOLEAN) || filter_var($s['SGC_TWO_FACTOR_ENABLED'] ?? false, FILTER_VALIDATE_BOOLEAN)) {
throw new LogicException('Geography base must remain enabled and MFA disabled.');
}
foreach (['warehouses', 'equipment'] as $table) {
if (Schema::connection('receipt_install')->hasColumn($table, 'geography_reference')) {
throw new LogicException('Operational geography already present; inspect instead of preparing again.');
}
}
$oldColumns = [];
foreach (['warehouses', 'equipment'] as $table) {
$oldColumns[$table] = Schema::connection('receipt_install')->getColumnListing($table);
}
$projected = function ($connection) use ($oldColumns) {
$out = [];
foreach ($oldColumns as $table => $columns) {
$selected = implode(',', array_map(fn ($c) => '"'.str_replace('"', '""', $c).'"', $columns));
$rows = $connection->select('select row_to_json(t)::text as row from (select '.$selected.' from "'.$table.'") t order by row_to_json(t)::text');
$out[$table] = hash('sha256', json_encode(array_column($rows, 'row'), JSON_THROW_ON_ERROR));
}
return $out;
};
$checkEmpty = function ($connection, $name) use ($tables, $oldColumns) {
foreach ($oldColumns as $table => $columns) {
if (Schema::connection($name)->getColumnListing($table) !== [...$columns, 'geography_reference']
|| $connection->table($table)->whereNotNull('geography_reference')->exists()) {
throw new LogicException('Unexpected geography structure or nonempty references.');
}
}
if (array_column($connection->select("select tablename from pg_tables where schemaname='public' order by tablename"), 'tablename') !== $tables) {
throw new LogicException('Unexpected table created.');
}
};
$restore = 'compras_pilot_restore_'.bin2hex(random_bytes(6));
$created = false;
try {
$db->beginTransaction();
$db->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY');
$baseline = $fingerprint($db, $tables);
$beforeRows = $projected($db);
$migrationCount = $db->table('migrations')->count();
$directory = 'C:/laragon/data/sgf-tempo/backups/compras-operational-geography-preparation-'.gmdate('Ymd-His').'-'.bin2hex(random_bytes(3));
if (! mkdir($directory, 0700, true)) {
throw new RuntimeException('Backup unavailable.');
}
$dump = $directory.'/before.dump';
$snapshot = $db->selectOne('select pg_export_snapshot() as snapshot')->snapshot;
$pg('pg_dump', ['--format=custom', '--snapshot='.$snapshot, '--file='.$dump, '--dbname='.$qa['database']], $qa);
$db->commit();
$admin->statement('CREATE DATABASE "'.$restore.'"');
$created = true;
$pg('pg_restore', ['--no-owner', '--no-privileges', '--exit-on-error', '--dbname='.$restore, $dump], $owner);
config(['database.connections.receipt_restore' => [...$owner, 'url' => null, 'database' => $restore]]);
$restored = DB::connection('receipt_restore');
if ($fingerprint($restored, $tables) !== $baseline) {
throw new LogicException('Restored backup differs.');
}
if (Artisan::call('migrate', ['--database' => 'receipt_restore', '--path' => $migration, '--force' => true]) !== 0) {
throw new RuntimeException('Disposable migration failed.');
}
$protected = array_values(array_diff($tables, ['warehouses', 'equipment', 'migrations']));
$checkEmpty($restored, 'receipt_restore');
if ($fingerprint($restored, $protected) !== array_intersect_key($baseline, array_flip($protected)) || $projected($restored) !== $beforeRows || $restored->table('migrations')->count() !== $migrationCount + 1) {
throw new LogicException('Unexpected dry-run changes.');
}
$result = ['checked_at' => gmdate('c'), 'result' => 'passed', 'environment' => 'http://127.0.0.1:8005', 'scope' => 'prepare_two_nullable_operational_geography_columns', 'migration' => $migration, 'migration_sha256' => hash_file('sha256', $root.'/'.$migration), 'backup' => $dump, 'backup_sha256' => hash_file('sha256', $dump), 'restored_tables_checked' => count($tables), 'protected_tables_checked' => count($protected), 'existing_warehouse_and_equipment_columns_preserved' => true, 'new_references_all_null' => true, 'pilot_migration_applied' => false, 'pilot_configuration_changed' => false, 'mfa_enabled' => false, 'restore_database_removed' => false];
} finally {
if ($db->transactionLevel() > 0) {
$db->rollBack();
}
DB::purge('receipt_restore');
if ($created) {
$admin->statement('DROP DATABASE "'.$restore.'" WITH (FORCE)');
}
}
$result['restore_database_removed'] = true;
file_put_contents($root.'/docs/proofs/operational-geography-schema-preparation.json', json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES).PHP_EOL);
echo 'Operational geography schema prepared only in restored copy; pilot unchanged.'.PHP_EOL;
+23
View File
@@ -0,0 +1,23 @@
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const source = await fs.readFile('scripts/supplier-evaluation-check.mjs', 'utf8');
const common = source.slice(source.indexOf('const base ='), source.indexOf('const author ='));
await new Function('fs', 'assert', 'return (async()=>{' + common + `
const records=[];
for(const role of ['admin','warehouse','procurement']) {
const viewer=client(); await viewer.enter(role);
assert.equal((await viewer.request('/contexto','POST',{area:'procurement',option:'procurement.internal'})).status,302);
const index=await viewer.request('/recepcoes'); assert.equal(index.status,200);
let checked=0;
for(const receipt of index.page.props.receipts.data.slice(0,2)) {
const page=await viewer.request('/recepcoes/'+receipt.id+'/imprimir','GET',undefined,false);
assert.equal(page.status,200);
assert.ok(page.text.includes('Referências documentais'));
assert.ok(page.text.includes('Confirmação original'));
checked++;
}
records.push({role,printedReceiptsChecked:checked});
}
await fs.writeFile('docs/proofs/receipt-print-http.json',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',records,business_commands:false,visual_review:false},null,2));
console.log('Reprodução imprimível consultada; sem movimentos ou decisões.');
` + '})()')(fs, assert);
+24
View File
@@ -0,0 +1,24 @@
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const source = await fs.readFile('scripts/supplier-evaluation-check.mjs', 'utf8');
const common = source.slice(source.indexOf('const base ='), source.indexOf('const author ='));
await new Function('fs', 'assert', 'return (async()=>{' + common + `
const viewer=client(); await viewer.enter('admin');
assert.equal((await viewer.request('/contexto','POST',{area:'people',option:'people.internal'})).status,302);
const index=await viewer.request('/pessoas'); assert.equal(index.status,200);
let dossiersChecked=0; let availabilityRows=0;
for(const process of index.page.props.processes.data.slice(0,2)) {
const dossier=await viewer.request('/pessoas/'+process.id+'/dossier.json','GET',undefined,false);
assert.equal(dossier.status,200);
assert.equal(dossier.page.schema,'sgc.people.process-dossier.v1');
assert.equal(dossier.page.effect,'preparation_only');
const page=await viewer.request('/pessoas/'+process.id); assert.equal(page.status,200);
assert.deepEqual(dossier.page.candidates,page.page.props.candidates);
availabilityRows+=dossier.page.candidates.filter(row=>row.received_availability).length;
assert.equal(dossier.page.process.tenant_id,undefined);
assert.equal(dossier.page.process.creation_hash,undefined);
dossiersChecked++;
}
await fs.writeFile('docs/proofs/received-availability-http.json',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',dossiersChecked,availabilityRows,business_commands:false,visual_review:false,coverage:'Existing visible processes only; positive received-availability cases exercised in disposable tests.'},null,2));
console.log('People page/dossier availability projection checked for existing visible sources only.');
` + '})()')(fs, assert);
+25
View File
@@ -0,0 +1,25 @@
import fs from 'node:fs/promises';
import assert from 'node:assert/strict';
const source = await fs.readFile('scripts/supplier-evaluation-check.mjs', 'utf8');
const common = source.slice(source.indexOf('const base ='), source.indexOf('const author ='));
await new Function('fs', 'assert', 'return (async()=>{' + common + `
const records=[];
for(const role of ['admin','warehouse']) {
const viewer=client(); await viewer.enter(role);
assert.equal((await viewer.request('/contexto','POST',{area:'procurement',option:'procurement.internal'})).status,302);
const index=await viewer.request('/stock/requisicoes'); assert.equal(index.status,200);
let documentsChecked=0,requestsChecked=0;
for(const request of index.page.props.records.data.slice(0,3)) {
const detail=await viewer.request('/stock/requisicoes/'+request.id); assert.equal(detail.status,200);
requestsChecked++;
for(const delivery of detail.page.props.progress.events.filter(e=>e.action==='deliver').slice(0,2)) {
const print=await viewer.request('/stock/requisicoes/'+request.id+'/entregas/'+delivery.id+'/imprimir','GET',undefined,false);
assert.equal(print.status,200); assert.ok(print.text.includes('Documento de saída interna'));
assert.ok(print.text.includes('Sem factura')); documentsChecked++;
}
}
records.push({role,requestsChecked,documentsChecked});
}
await fs.writeFile('docs/proofs/warehouse-delivery-print-http.json',JSON.stringify({checked_at:new Date().toISOString(),environment:base,result:'passed',records,business_commands:false,visual_review:false,coverage:'Existing records only; complete delivery scenarios exercised in disposable databases.'},null,2));
console.log('Consultas de armazém preservadas; sem criar entregas no piloto.');
` + '})()')(fs, assert);
+100 -1
View File
@@ -58,12 +58,30 @@ $noticeConsultation = in_array('--notice-consultation', $argv ?? [], true);
$agreementSources = in_array('--agreement-sources', $argv ?? [], true);
$mfaFoundation = in_array('--mfa-foundation', $argv ?? [], true);
$mfaManagement = in_array('--mfa-management', $argv ?? [], true);
$mfaEvaluation = in_array('--mfa-evaluation', $argv ?? [], true);
$peopleDossier = in_array('--people-dossier', $argv ?? [], true);
$auditMetadata = in_array('--audit-metadata', $argv ?? [], true);
$equipmentIntegration = in_array('--equipment-integration', $argv ?? [], true);
$equipmentWarehouse = in_array('--equipment-warehouse', $argv ?? [], true);
$receivedAvailability = in_array('--received-availability', $argv ?? [], true);
$candidateTerritory = in_array('--candidate-territory', $argv ?? [], true);
$candidateAdditionalGeography = in_array('--candidate-additional-geography', $argv ?? [], true);
$candidateGeography = in_array('--candidate-geography', $argv ?? [], true);
$operationalGeography = in_array('--operational-geography', $argv ?? [], true);
$geography = in_array('--geography', $argv ?? [], true);
$issuedCancellation = in_array('--issued-cancellation', $argv ?? [], true);
$requisitionAudit = in_array('--requisition-audit', $argv ?? [], true);
$auditPagination = in_array('--audit-pagination', $argv ?? [], true);
$neededAttention = in_array('--needed-attention', $argv ?? [], true);
$approvedAttention = in_array('--approved-attention', $argv ?? [], true);
$replenishmentHealth = in_array('--replenishment-health', $argv ?? [], true);
$receiptBlock = in_array('--receipt-block', $argv ?? [], true);
$receiptPrint = in_array('--receipt-print', $argv ?? [], true);
$receiptHealth = in_array('--receipt-health', $argv ?? [], true);
$operationalHealth = in_array('--operational-health', $argv ?? [], true);
$warehouseDeliveryPrint = in_array('--warehouse-delivery-print', $argv ?? [], true);
$warehouseRequestPrint = in_array('--warehouse-request-print', $argv ?? [], true);
$warehouseRequestExport = in_array('--warehouse-request-export', $argv ?? [], true);
$inbox = in_array('--inbox', $argv ?? [], true) || $transport;
$warehouse = in_array('--warehouse', $argv ?? [], true) || $pilot || $workdesk || $readiness;
try {
@@ -188,6 +206,39 @@ try {
if ($mfaManagement) {
$tests = ['tests/Feature/Settings/TwoFactorManagementTest.php'];
}
if ($mfaEvaluation) {
$tests = ['tests/Feature/Auth/MfaEvaluationBoundaryTest.php'];
}
if ($peopleDossier) {
$tests = ['tests/Feature/PeopleHiringTest.php'];
}
if ($auditMetadata) {
$tests = ['tests/Feature/AuditMetadataBlockTest.php'];
}
if ($equipmentIntegration || $equipmentWarehouse) {
$tests = ['tests/Feature/EquipmentSparePartsTest.php'];
}
if ($receivedAvailability) {
$tests = ['tests/Feature/CandidateSubmissionsTest.php'];
}
if ($candidateTerritory) {
$tests = ['tests/Feature/CandidateSubmissionsTest.php'];
}
if ($candidateAdditionalGeography) {
$tests = ['tests/Feature/CandidateGeographyTest.php', 'tests/Feature/CandidateSubmissionsTest.php'];
}
if ($candidateGeography) {
$tests = ['tests/Feature/CandidateGeographyTest.php', 'tests/Feature/CandidateSubmissionsTest.php'];
}
if ($operationalGeography) {
$tests = ['tests/Feature/OperationalGeographyTest.php'];
}
if ($geography) {
$tests = ['tests/Feature/AdministrativeGeographyTest.php', 'tests/Feature/AdministrativeGeographyReviewTest.php'];
}
if ($issuedCancellation) {
$tests = ['tests/Feature/IssuedOrderCancellationTest.php'];
}
if ($requisitionAudit || $auditPagination) {
$tests = ['tests/Feature/InternalRequisitionCandidateTest.php'];
}
@@ -200,7 +251,33 @@ try {
if ($receiptBlock) {
$tests = ['tests/Feature/ReceiptDocumentBlockTest.php'];
}
if ($receiptPrint) {
$tests = ['tests/Feature/ReceiptPrintBlockTest.php'];
}
if ($receiptHealth) {
$tests = ['tests/Feature/ReceiptDocumentHealthTest.php'];
}
if ($operationalHealth) {
$tests = ['tests/Feature/OperationalHealthTest.php'];
}
if ($warehouseDeliveryPrint || $warehouseRequestPrint || $warehouseRequestExport) {
$tests = ['tests/Feature/WarehouseFulfilmentTest.php'];
}
$filter = match (true) {
$receivedAvailability => ['--filter=received availability projection'],
$candidateTerritory => ['--filter=candidate territory'],
$issuedCancellation => ['--filter=issued cancellation'],
$equipmentWarehouse => ['--filter=equipment warehouse requests|reuses the stock operation'],
$equipmentIntegration => ['--filter=equipment integration block'],
$auditMetadata => ['--filter=audit metadata block'],
$peopleDossier => ['--filter=people dossier block'],
$mfaEvaluation => ['--filter=mfa evaluation boundary'],
$operationalHealth => ['--filter=operational health'],
$receiptHealth => ['--filter=receipt document health'],
$warehouseRequestExport => ['--filter=warehouse request export'],
$warehouseRequestPrint => ['--filter=warehouse request print'],
$warehouseDeliveryPrint => ['--filter=warehouse delivery print block'],
$receiptPrint => ['--filter=receipt print block'],
$receiptBlock => ['--filter=receipt document block'],
$replenishmentHealth => ['--filter=replenishment health'],
$approvedAttention => ['--filter=approved attention reports'],
@@ -238,13 +315,17 @@ try {
$awardTasks => ['--filter=task inbox'],
default => [],
};
$process = new Process([PHP_BINARY, 'vendor/bin/pest', '--compact', ...$tests, ...$filter], dirname(__DIR__), $environment, timeout: $financeIntegration || $awardTasks || $quotationTasks || $organizationPreview || $pilotAccessProposal || $formalTasks || $supplyTasks || $historyTasks || $suggestionTasks || $alternativeTasks || $supplierTasks || $dispositionTasks || $inventoryTasks || $lotTasks || $improvementTasks || $qualityTasks || $coordinationTasks || $lotQualityTasks || $lotPagination || $supplyPagination || $correctionPagination || $reservationSources || $historySources || $policySources || $correctionSources || $supplyLineSources || $noticeConsultation ? 300 : 120);
$process = new Process([PHP_BINARY, 'vendor/bin/pest', '--compact', ...$tests, ...$filter], dirname(__DIR__), $environment, timeout: $equipmentWarehouse || $operationalHealth || $warehouseRequestExport || $receivedAvailability || $candidateTerritory || $candidateAdditionalGeography || $candidateGeography || $operationalGeography || $geography || $financeIntegration || $awardTasks || $quotationTasks || $organizationPreview || $pilotAccessProposal || $formalTasks || $supplyTasks || $historyTasks || $suggestionTasks || $alternativeTasks || $supplierTasks || $dispositionTasks || $inventoryTasks || $lotTasks || $improvementTasks || $qualityTasks || $coordinationTasks || $lotQualityTasks || $lotPagination || $supplyPagination || $correctionPagination || $reservationSources || $historySources || $policySources || $correctionSources || $supplyLineSources || $noticeConsultation || $peopleDossier ? 300 : 120);
$process->run();
echo $process->getOutput();
if (! $process->isSuccessful()) {
throw new RuntimeException('Prova PostgreSQL de contexto não aprovada.');
}
$races = [];
if ($issuedCancellation) {
require __DIR__.'/../tests/Support/order-cancellation-pg-races.php';
$races = orderCancellationRaces($environment, $config, $database);
}
if ($inbox) {
require __DIR__.'/../tests/Support/inbox-pg-races.php';
$races = inboxPgRaces($environment, $config, $database);
@@ -367,6 +448,24 @@ try {
DB::purge('warehouse_proof_read');
}
$proofName = match (true) {
$receivedAvailability => 'received-availability-pg',
$candidateTerritory => 'candidate-territory-pg',
$candidateAdditionalGeography => 'candidate-additional-geography-pg',
$candidateGeography => 'candidate-geography-pg',
$operationalGeography => 'operational-geography-pg',
$geography => 'administrative-geography-review-pg',
$issuedCancellation => 'issued-order-cancellation-pg',
$equipmentWarehouse => 'equipment-warehouse-pg',
$equipmentIntegration => 'equipment-integration-pg',
$auditMetadata => 'audit-metadata-pg',
$peopleDossier => 'people-dossier-pg',
$mfaEvaluation => 'mfa-evaluation-boundary-pg',
$operationalHealth => 'operational-health-pg',
$receiptHealth => 'receipt-document-health-pg',
$warehouseRequestExport => 'warehouse-request-export-pg',
$warehouseRequestPrint => 'warehouse-request-print-pg',
$warehouseDeliveryPrint => 'warehouse-delivery-print-pg',
$receiptPrint => 'receipt-print-pg',
$receiptBlock => 'receipt-block-pg',
$replenishmentHealth => 'replenishment-health-pg',
$approvedAttention => 'approved-attention-pg',