gea-program 0.42.0__tar.gz → 0.43.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gea_program-0.42.0 → gea_program-0.43.0}/PKG-INFO +14 -1
- {gea_program-0.42.0 → gea_program-0.43.0}/README.md +13 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/__init__.py +1 -1
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/__main__.py +80 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/acceptance_tests.py +207 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/client_reports.py +5 -0
- gea_program-0.43.0/gea/dossier.py +369 -0
- gea_program-0.43.0/gea/dossier_verify.py +136 -0
- gea_program-0.43.0/gea/ed25519.py +131 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/files.py +3 -1
- gea_program-0.43.0/gea/help/dossier.md +15 -0
- gea_program-0.43.0/gea/help/report-history.md +11 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/helplib.py +2 -0
- gea_program-0.43.0/gea/report_history.py +148 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/service.py +37 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/web/app.html +32 -1
- {gea_program-0.42.0 → gea_program-0.43.0}/gea_program.egg-info/PKG-INFO +14 -1
- {gea_program-0.42.0 → gea_program-0.43.0}/gea_program.egg-info/SOURCES.txt +6 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/pyproject.toml +1 -1
- {gea_program-0.42.0 → gea_program-0.43.0}/LICENSE +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/BENCH_TEST_PROTOCOL.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/accuracy_statement.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/alarm_engine.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/backup.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/bench.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/blind_harness.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/acex_lomonosov_age_depth_model.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/acex_lomonosov_age_depth_model.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/agassiz77_canada_temperature.csv +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/agassiz77_canada_temperature.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/barbados_110_consolidation.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/barbados_110_consolidation.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/bengal_u1452_grain_size.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/bengal_u1452_grain_size.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/blake_164_methane_isotopes.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/blake_164_methane_isotopes.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/chicxulub_m0077a_pwave_velocity.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/collingwood_1_28_ks_complete.las +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/collingwood_1_28_ks_complete.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/costa_rica_odp_friction_envelope.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/costa_rica_odp_friction_envelope.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/dead_sea_5017_debrite_xrf_ms.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/dsdp_504b_physical_properties.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/dsdp_504b_physical_properties.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/dsdp_504b_sound_velocity.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/dsdp_504b_sound_velocity.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/elgygytgyn_5011_turbidites.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/elgygytgyn_5011_turbidites.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/epica_domec_co2_800kyr.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/epica_domec_co2_800kyr.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/fram_909_organic_petrography.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/fram_909_organic_petrography.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/gbr_325_coral_uth_ages.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/gbr_325_coral_uth_ages.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/gisp2_greenland_temperature.csv +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/gisp2_greenland_temperature.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/gom_308_t2p_insitu.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/gom_308_t2p_insitu.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/guaymas_385_dom_d13c.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/guaymas_385_dom_d13c.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/hikurangi_u1520_friction_insitu.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/hikurangi_u1520_friction_insitu.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/hydrate_ridge_204_ncr_hydrate.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/iodp_u1324_pore_pressure.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/iodp_u1324_pore_pressure.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/jfast_c0019_slow_slip_events.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/jfast_c0019_slow_slip_events.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/kennetcook_2_p129_excerpt.las +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/kennetcook_2_p129_excerpt.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_hb_bhgm_density.dat +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_hb_bhgm_density.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_hb_complog_6020_excerpt.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_hb_complog_6020_excerpt.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_hb_hlog246_temperature.dat +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_hb_hlog246_temperature.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_hb_rockmech_compress.dat +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_hb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.dat +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_hb_tvd_0_9080_excerpt.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_vb_rockmech_compress.dat +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_vb_rockmech_compress.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_vb_vlog251_temperature.dat +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ktb_vb_vlog251_temperature.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/l06_06_nl_survey.csv +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/l06_06_nl_survey.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/l07_01_nl_excerpt.las +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/l07_01_nl_excerpt.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/mariana_1200_serpentinite_geochem.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/mariana_1200_serpentinite_geochem.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/med_160_sapropels.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/med_160_sapropels.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/nankai_megasplay_shear_strength.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/nankai_megasplay_shear_strength.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_1027b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_1027b_thermal_conductivity.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_1027c_cork_temperature.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_1027c_cork_temperature.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_1165b_thermal_conductivity.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_1165b_thermal_conductivity.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_1274a_mantle_peridotite_mad.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_504b_dike_elastic_moduli.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_504b_dike_elastic_moduli.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_504b_leg137_borehole_fluids.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_504b_leg137_borehole_fluids.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/odp_735b_gabbro_elastic_moduli.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/peru_201_sulfate_reduction.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/peru_201_sulfate_reduction.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/scorpio_e1_sa_excerpt.las +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/scorpio_e1_sa_excerpt.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/sumatra_362_cohesion.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/sumatra_362_cohesion.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/university_6_17_no1_tx_excerpt.las +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/university_6_17_no1_tx_excerpt.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ursa_308_xrd_mineralogy.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/ursa_308_xrd_mineralogy.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/volve_15_9_19_sr_excerpt.las +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/volve_15_9_19_sr_excerpt.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/volve_15_9_19a_core_excerpt.csv +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/volve_15_9_19a_core_excerpt.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/volve_f12_f14_production_excerpt.csv +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/volve_f12_f14_production_excerpt.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/walvis_208_petm_carbonate.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/walvis_208_petm_carbonate.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/woodlark_1109_rock_eval.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog/woodlark_1109_rock_eval.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog_map.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/catalog_register.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/certificates.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/cli.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/config_versioning.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/conformance.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/control_room.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/correlation.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/dashboard.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/declarations.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/deviation.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/dlis.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/dnp3.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/doctor.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/downhole_engine.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/drift_monitor.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/drill_string.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/earth_model.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/economics.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/edr.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/elevation.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/etp.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/etp12_schemas.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/example_register_map.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/fat_sat.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/fixtures/README.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/fixtures/comcat_delaware_basin_2026-09.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/fixtures/comcat_mahoning_1990-2026.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/fixtures/comcat_youngstown_2011-2012.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/fixtures/ne_110m_coastline.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/follower.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/forward_model.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/friction_priors.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/gamma.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/gauge_aging.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/gauge_specs.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/geodesy.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/gravity_reference.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/hartip.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/TESTER_GUIDE.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/alarms.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/audit-update.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/backup.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/catalog.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/charts.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/conformance.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/control-room.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/data-in.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/declare.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/dlis.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/doctor.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/drift.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/drillstring.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/economics.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/edr.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/etp.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/field-ports.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/files.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/historian.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/instruments.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/interval.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/map.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/month-end.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/notifications.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/opseis.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/osdu.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/patches.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/penetrator.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/ppdm.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/quakeml.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/quality.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/seedlink.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/seismic.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/setup.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/simulation.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/site.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/sites.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/slip.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/soak.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/sra.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/start.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/structure.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/tools.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/transients.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/upkeep.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/vibration.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/well-report.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/well-tests.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/help/well3d.md +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/housekeeping.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/interval.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/inverse_engine.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/jobs.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/live_ports.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/loadtest.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/matplotlib_demo.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/modbus.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/modbus_rtu.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/model_card.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/month_end.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/mqtt_port.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/notify.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/op_seismicity.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/opcua_port.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/operator_app.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/osdu.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/patches.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/penetrator.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/permits.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/piwebapi.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/ports.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/ppdm.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/profile_catalog.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/project.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/qt6_downhole_app.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/quakeml.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reconciler.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/IU_ANMO_10_BHZ_response.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/IU_ANMO_10_BHZ_response.xml +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/eia_henry_hub_daily.csv.gz +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/eia_prices.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/eia_wti_daily.csv.gz +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/libmseed_steim.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/libmseed_steim1_4096.mseed +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/libmseed_steim2_4096.mseed +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/libmseed_steim2_512.mseed +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/mahoning_example.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/mud_motor_specs.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/penetrator_ratings.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/seismicity_protocols.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/tool_sources.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/us_outline.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/us_outline.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/volve_3d.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/volve_f4_interpretation.las.gz +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/volve_f4_logs.provenance.json +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/volve_f4_lwd.las.gz +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/volve_surfaces.json.gz +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/volve_traj_F-10.xml.gz +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/volve_traj_F-4.xml.gz +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/volve_traj_F-5_12.25in.xml.gz +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/volve_traj_F-5_17.5in.xml.gz +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/volve_traj_F-5_36in.xml.gz +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/volve_traj_F-5_8.5in.xml.gz +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/reference/volve_well_picks.csv.gz +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/rock_inventory.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/sample_record.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/sample_well_profile.csv +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/sbom.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seedlink.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/segy.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seismic.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seismic_array.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seismic_assoc.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seismic_detect.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seismic_film.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seismic_harmonic.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seismic_qc.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seismic_response.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seismic_signature.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seismic_track.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seismic_uncertainty.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/seismic_unlisted.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/sensor_swap.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/series_cache.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/service_life.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/setup_checklist.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/shapefile.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/shell.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/shut_in.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/simulation.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/site_map.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/sla_report.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/slip.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/soak.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/sra.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/store_forward.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/strata_join.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/structure.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/supervisor.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/survey_cmd.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/survey_view.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/telemetry.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/tool_catalog.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/tool_library.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/tool_taxonomy.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/transient.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/vibration.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/well3d.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/well_assembler.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/well_report.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/well_test_validation.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/wits0.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/witsml.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea/workspace.py +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea_program.egg-info/dependency_links.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea_program.egg-info/entry_points.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea_program.egg-info/requires.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/gea_program.egg-info/top_level.txt +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/setup.cfg +0 -0
- {gea_program-0.42.0 → gea_program-0.43.0}/tests/test_acceptance.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gea-program
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.43.0
|
|
4
4
|
Summary: GEA-Program: downhole gauge monitoring - canonical measurement records, quality rules, drift evaluation with a re-fit change log, well-test validation, alarm management, model cards, store-and-forward, monthly SLA measurement, FAT/SAT protocols and a dashboard, generated from live objects in the client's reporting outline.
|
|
5
5
|
Author: Daniel T. Murphy
|
|
6
6
|
License: MPL-2.0
|
|
@@ -648,6 +648,19 @@ against it; `gea seedlink --config ... --hello` prints what a server says of
|
|
|
648
648
|
itself; `gea help seedlink`. A TexNet station is served by EarthScope at
|
|
649
649
|
`rtserve.iris.washington.edu:18000`, network `TX`.
|
|
650
650
|
|
|
651
|
+
### Report history and the signed dossier
|
|
652
|
+
|
|
653
|
+
Every client report a workspace writes is kept, version by version, under
|
|
654
|
+
`reports\history\` with each file's SHA-256, so pressing a report button
|
|
655
|
+
again no longer loses the last one; the Reports tab lists every version.
|
|
656
|
+
The signed dossier puts a well's - or the pad's - reports, declarations,
|
|
657
|
+
audit log and source-record hashes in one zip, signed with the site's own
|
|
658
|
+
Ed25519 key (made on the site's machine, never sent anywhere), with a
|
|
659
|
+
checker inside that anyone can run with plain Python: VALID when the
|
|
660
|
+
signature and every file's hash hold, and inside the workspace a check that
|
|
661
|
+
the source records and the audit log still match what was signed.
|
|
662
|
+
`gea dossier`, `gea reports-history`, `gea help dossier`.
|
|
663
|
+
|
|
651
664
|
### Operations and seismicity
|
|
652
665
|
|
|
653
666
|
The Operations & Seismicity tab sets each well's drilling, completion and
|
|
@@ -609,6 +609,19 @@ against it; `gea seedlink --config ... --hello` prints what a server says of
|
|
|
609
609
|
itself; `gea help seedlink`. A TexNet station is served by EarthScope at
|
|
610
610
|
`rtserve.iris.washington.edu:18000`, network `TX`.
|
|
611
611
|
|
|
612
|
+
### Report history and the signed dossier
|
|
613
|
+
|
|
614
|
+
Every client report a workspace writes is kept, version by version, under
|
|
615
|
+
`reports\history\` with each file's SHA-256, so pressing a report button
|
|
616
|
+
again no longer loses the last one; the Reports tab lists every version.
|
|
617
|
+
The signed dossier puts a well's - or the pad's - reports, declarations,
|
|
618
|
+
audit log and source-record hashes in one zip, signed with the site's own
|
|
619
|
+
Ed25519 key (made on the site's machine, never sent anywhere), with a
|
|
620
|
+
checker inside that anyone can run with plain Python: VALID when the
|
|
621
|
+
signature and every file's hash hold, and inside the workspace a check that
|
|
622
|
+
the source records and the audit log still match what was signed.
|
|
623
|
+
`gea dossier`, `gea reports-history`, `gea help dossier`.
|
|
624
|
+
|
|
612
625
|
### Operations and seismicity
|
|
613
626
|
|
|
614
627
|
The Operations & Seismicity tab sets each well's drilling, completion and
|
|
@@ -566,6 +566,25 @@ def main(argv=None) -> int:
|
|
|
566
566
|
p_os.add_argument("--actor", type=str, default="cli")
|
|
567
567
|
p_os.add_argument("--json", action="store_true")
|
|
568
568
|
|
|
569
|
+
p_dz = sub.add_parser("dossier", help="the signed dossier: a well's (or the pad's) reports, declarations, audit log and source hashes in one zip, signed with the site's Ed25519 key, with a checker anyone can run without this program")
|
|
570
|
+
p_dz.add_argument("--workspace", type=str, default=None)
|
|
571
|
+
p_dz.add_argument("--well", type=str, default=None, help="a well; without it, the pad (every well and the site reports)")
|
|
572
|
+
p_dz.add_argument("--include-sources", action="store_true", help="embed the source records (by default they are listed by hash)")
|
|
573
|
+
p_dz.add_argument("--verify", type=str, default=None, help="a dossier to check (with --workspace, also against this site)")
|
|
574
|
+
p_dz.add_argument("--sources", type=str, default="", help="with --verify: a folder holding the source records to check against their hashes")
|
|
575
|
+
p_dz.add_argument("--key", action="store_true", help="print this site's signing key fingerprint")
|
|
576
|
+
p_dz.add_argument("--list", action="store_true", help="list the dossiers this site has signed")
|
|
577
|
+
p_dz.add_argument("--actor", type=str, default="cli")
|
|
578
|
+
p_dz.add_argument("--json", action="store_true")
|
|
579
|
+
|
|
580
|
+
p_rh = sub.add_parser("reports-history", help="every version of every client report this workspace has written, kept under reports/history; --prune keeps the newest N")
|
|
581
|
+
p_rh.add_argument("--workspace", type=str, required=True)
|
|
582
|
+
p_rh.add_argument("--family", type=str, default=None, help="e.g. wells/Well-1/well_report or pad_report")
|
|
583
|
+
p_rh.add_argument("--prune", action="store_true")
|
|
584
|
+
p_rh.add_argument("--keep", type=int, default=0)
|
|
585
|
+
p_rh.add_argument("--apply", action="store_true", help="with --prune: remove (without it, list what would go)")
|
|
586
|
+
p_rh.add_argument("--json", action="store_true")
|
|
587
|
+
|
|
569
588
|
p_sm = sub.add_parser("simulation", help="the simulation in words: the scenes (Volve 15/9-F-4 with its logs and interpretation, Volve F-5 and F-10 on the survey clock, every drilling-recorder well), and what the record says at a depth (the Simulation tab replays it)")
|
|
570
589
|
p_sm.add_argument("--workspace", type=str, default=None)
|
|
571
590
|
p_sm.add_argument("--scene", type=str, default=None, help="e.g. volve-f4, or well:Well-30636033")
|
|
@@ -2226,6 +2245,67 @@ def main(argv=None) -> int:
|
|
|
2226
2245
|
return 0
|
|
2227
2246
|
print(_json.dumps(r, default=str) if a.json else _OS.text(r))
|
|
2228
2247
|
return 0
|
|
2248
|
+
elif a.cmd == "dossier":
|
|
2249
|
+
import json as _json
|
|
2250
|
+
from . import dossier as _DZ
|
|
2251
|
+
from .cli import _safe_stdout
|
|
2252
|
+
from .workspace import Workspace, WorkspaceError
|
|
2253
|
+
_safe_stdout()
|
|
2254
|
+
ws = None
|
|
2255
|
+
if a.workspace:
|
|
2256
|
+
try:
|
|
2257
|
+
ws = Workspace(a.workspace)
|
|
2258
|
+
except WorkspaceError as e:
|
|
2259
|
+
raise SystemExit(f"dossier: {e}")
|
|
2260
|
+
if a.verify:
|
|
2261
|
+
r = _DZ.verify(a.verify, ws, a.sources)
|
|
2262
|
+
print(_json.dumps(r, default=str) if a.json else _DZ.text(r))
|
|
2263
|
+
return 0 if r["status"] == "VALID" else 1
|
|
2264
|
+
if ws is None:
|
|
2265
|
+
raise SystemExit("dossier: give --workspace (or --verify FILE)")
|
|
2266
|
+
if a.key:
|
|
2267
|
+
k = _DZ.key_info(ws)
|
|
2268
|
+
print(f"Ed25519 {k['fingerprint']} (public key {k['public_key']}, made {k['created_utc']})" if k else "no signing key yet: the first dossier makes one")
|
|
2269
|
+
return 0
|
|
2270
|
+
if a.list:
|
|
2271
|
+
for e in reversed(_DZ.ledger(ws)):
|
|
2272
|
+
print(f"{e['utc']} {e['dossier_id']} {e['display']:<24} {e['n_files']:>4} files {e['path']}")
|
|
2273
|
+
return 0
|
|
2274
|
+
try:
|
|
2275
|
+
e = _DZ.build(ws, a.actor, __version__, a.well, a.include_sources)
|
|
2276
|
+
except (KeyError, ValueError) as ex:
|
|
2277
|
+
raise SystemExit(f"dossier: {ex.args[0] if ex.args else ex}")
|
|
2278
|
+
print(f"signed {e['dossier_id']}: {e['display']}, {e['n_files']} file(s), {e['n_sources']} source record(s) {'embedded' if e['sources_embedded'] else 'by hash'}")
|
|
2279
|
+
print(f" {os.path.join(ws.reports_dir, e['path'])}")
|
|
2280
|
+
print(f" key fingerprint {e['fingerprint']}")
|
|
2281
|
+
return 0
|
|
2282
|
+
elif a.cmd == "reports-history":
|
|
2283
|
+
import json as _json
|
|
2284
|
+
from . import report_history as _RH
|
|
2285
|
+
from .cli import _safe_stdout
|
|
2286
|
+
from .workspace import Workspace, WorkspaceError
|
|
2287
|
+
_safe_stdout()
|
|
2288
|
+
try:
|
|
2289
|
+
ws = Workspace(a.workspace)
|
|
2290
|
+
except WorkspaceError as e:
|
|
2291
|
+
raise SystemExit(f"reports-history: {e}")
|
|
2292
|
+
if a.prune:
|
|
2293
|
+
if a.keep < 1:
|
|
2294
|
+
raise SystemExit("reports-history: --prune needs --keep N (at least 1)")
|
|
2295
|
+
r = _RH.prune(ws.reports_dir, a.keep, a.family, a.apply)
|
|
2296
|
+
print(f"{'removed' if r['applied'] else 'would remove'} {len(r['removed'])} version(s), {r['bytes_freed']:,} bytes" + ("" if r['applied'] else " - add --apply to remove them"))
|
|
2297
|
+
return 0
|
|
2298
|
+
sm = _RH.summary(ws.reports_dir)
|
|
2299
|
+
if a.json:
|
|
2300
|
+
print(_json.dumps(sm, default=str)); return 0
|
|
2301
|
+
print(f"{sm['n_versions']} version(s) of {len(sm['families'])} report(s), {sm['bytes']:,} bytes under {os.path.join(ws.reports_dir, 'history')}")
|
|
2302
|
+
for f_ in sm["families"]:
|
|
2303
|
+
if a.family and f_["family"] != a.family:
|
|
2304
|
+
continue
|
|
2305
|
+
print(f" {f_['family']}: {f_['n']} version(s)")
|
|
2306
|
+
for v in f_["versions"][: (50 if a.family else 3)]:
|
|
2307
|
+
print(f" {v['utc']} {v.get('report_id') or ''} reports/{v['dir']}")
|
|
2308
|
+
return 0
|
|
2229
2309
|
elif a.cmd == "simulation":
|
|
2230
2310
|
import json as _json
|
|
2231
2311
|
from . import simulation as _SIM
|
|
@@ -9910,6 +9910,212 @@ def section_ck_operations_seismicity(tmp: str) -> None:
|
|
|
9910
9910
|
+ (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
9911
9911
|
|
|
9912
9912
|
|
|
9913
|
+
def section_cl_history_and_dossier(tmp: str) -> None:
|
|
9914
|
+
"""Section CL - report history and the signed dossier: Ed25519 against RFC 8032's test vectors and an independent
|
|
9915
|
+
implementation's signatures; every client report written in a workspace kept by version with its hashes, none kept
|
|
9916
|
+
outside one; a dossier signed, checked by its own standalone checker in a bare Python, and found INVALID when a file,
|
|
9917
|
+
the manifest or the signature is changed, and VALID BUT CHANGED when the source record or an earlier audit line is;
|
|
9918
|
+
the dossier chain; the API, the CLI, the Reports tab and the help pages."""
|
|
9919
|
+
import http.cookiejar
|
|
9920
|
+
import subprocess as _sp
|
|
9921
|
+
import urllib.request
|
|
9922
|
+
import urllib.error
|
|
9923
|
+
import zipfile
|
|
9924
|
+
import base64 as _b64
|
|
9925
|
+
import hashlib as _hl
|
|
9926
|
+
from . import __version__
|
|
9927
|
+
from . import client_reports as CRP
|
|
9928
|
+
from . import dossier as DZ
|
|
9929
|
+
from . import drill_string as DS
|
|
9930
|
+
from . import ed25519 as ED
|
|
9931
|
+
from . import helplib as H
|
|
9932
|
+
from . import report_history as RH
|
|
9933
|
+
from . import well_report as WR
|
|
9934
|
+
from .workspace import Workspace
|
|
9935
|
+
from .service import Service, Users
|
|
9936
|
+
pkg = Path(__file__).parent
|
|
9937
|
+
d = Path(tmp, "cl"); d.mkdir()
|
|
9938
|
+
|
|
9939
|
+
# -- CL1 the signature -------------------------------------------------------------------------------------------
|
|
9940
|
+
vec = [("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", "",
|
|
9941
|
+
"e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"),
|
|
9942
|
+
("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", "72",
|
|
9943
|
+
"92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00"),
|
|
9944
|
+
("c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7", "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025", "af82",
|
|
9945
|
+
"6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a")]
|
|
9946
|
+
rfc = all(ED.public_key(bytes.fromhex(s)).hex() == pk and ED.sign(bytes.fromhex(s), bytes.fromhex(m)).hex() == sg
|
|
9947
|
+
and ED.verify(bytes.fromhex(pk), bytes.fromhex(m), bytes.fromhex(sg)) for s, pk, m, sg in vec)
|
|
9948
|
+
s0, pk0, _, sg0 = vec[0]
|
|
9949
|
+
tamper = (not ED.verify(bytes.fromhex(pk0), b"x", bytes.fromhex(sg0)) and not ED.verify(bytes.fromhex(vec[1][1]), b"", bytes.fromhex(sg0))
|
|
9950
|
+
and not ED.verify(bytes.fromhex(pk0), b"", bytes.fromhex(sg0[:-2] + "0c")) and not ED.verify(b"\x00" * 31, b"", bytes.fromhex(sg0)))
|
|
9951
|
+
rng = __import__("random").Random(43)
|
|
9952
|
+
cross = True
|
|
9953
|
+
for _ in range(5): # random keys and messages: what is signed verifies, and nothing else does
|
|
9954
|
+
seed = bytes(rng.getrandbits(8) for _ in range(32)); msg = bytes(rng.getrandbits(8) for _ in range(77))
|
|
9955
|
+
sg_ = ED.sign(seed, msg)
|
|
9956
|
+
cross = cross and ED.verify(ED.public_key(seed), msg, sg_) and not ED.verify(ED.public_key(seed), msg[:-1], sg_)
|
|
9957
|
+
c1 = {"rfc8032": rfc, "tamper": tamper, "independent": cross, "fingerprint": ED.fingerprint(bytes.fromhex(pk0)).count(" ") == 7}
|
|
9958
|
+
failed1 = [k for k, v in c1.items() if not v]
|
|
9959
|
+
ok(not failed1,
|
|
9960
|
+
"CL1 Ed25519 in the standard library: RFC 8032's three test vectors signed and verified byte for byte; a changed message, another key, "
|
|
9961
|
+
"a changed signature byte and a malformed key refused; five random keys and messages verified, and refused once shortened"
|
|
9962
|
+
+ (f" [failed: {', '.join(failed1)}]" if failed1 else ""))
|
|
9963
|
+
|
|
9964
|
+
# -- CL2 the report history --------------------------------------------------------------------------------------
|
|
9965
|
+
syn = DS.synthetic_motor_record(str(d))
|
|
9966
|
+
wsp = str(d / "ws"); ws = Workspace.create(wsp, "Pad CL", actor="tester")
|
|
9967
|
+
w = ws.add_well_file(syn["path"], display="SYNTHETIC well", actor="tester")
|
|
9968
|
+
ws.refresh_dashboard(actor="tester")
|
|
9969
|
+
r1 = WR.write_well(ws, w["id"], __version__, actor="tester")
|
|
9970
|
+
r2 = WR.write_well(ws, w["id"], __version__, actor="tester")
|
|
9971
|
+
WR.write_pad(ws, __version__, actor="tester")
|
|
9972
|
+
fam = f"wells/{w['id']}/well_report"
|
|
9973
|
+
vs = RH.entries(ws.reports_dir, fam)
|
|
9974
|
+
cur = Path(ws.reports_dir, "wells", w["id"], "well_report.html").read_bytes()
|
|
9975
|
+
newest = Path(ws.reports_dir, vs[0]["dir"], "well_report.html").read_bytes() if vs else b""
|
|
9976
|
+
oldest = json.loads(Path(ws.reports_dir, vs[-1]["dir"], "well_report.json").read_text(encoding="utf-8")) if vs else {}
|
|
9977
|
+
outside = d / "out"
|
|
9978
|
+
CRP.write(CRP.Document(title="SYNTHETIC outside", report_id="OUT-1", front=[], sections=[]), str(outside), basename="x")
|
|
9979
|
+
out_ok = RH.locate(str(outside)) is None and not (outside / "history").exists() and (outside / "x.html").is_file()
|
|
9980
|
+
sm = RH.summary(ws.reports_dir)
|
|
9981
|
+
pr = RH.prune(ws.reports_dir, 1, fam)
|
|
9982
|
+
c2 = {
|
|
9983
|
+
"versions": len(vs) == 2 and vs[0]["report_id"] == r2["report_id"] and vs[1]["report_id"] == r1["report_id"] and newest == cur
|
|
9984
|
+
and oldest.get("report_id", r1["report_id"]) == r1["report_id"],
|
|
9985
|
+
"hashes": all(_hl.sha256(Path(ws.reports_dir, v["dir"], f["name"]).read_bytes()).hexdigest() == f["sha256"] for v in vs for f in v["files"])
|
|
9986
|
+
and any(f["name"].endswith(".svg") for f in vs[0]["files"]),
|
|
9987
|
+
"families": {"pad_report", f"wells/{w['id']}/drilling_record"} <= {f["family"] for f in sm["families"]} and sm["bytes"] > 0,
|
|
9988
|
+
"outside": out_ok and RH.locate(str(pkg.parent / "docs" / "report_samples")) is None,
|
|
9989
|
+
"prune": not pr["applied"] and len(pr["removed"]) == 1 and len(RH.entries(ws.reports_dir, fam)) == 2,
|
|
9990
|
+
"listing": "history" not in CRP.__dict__ and all(not x.startswith("history") for x in os.listdir(Path(ws.reports_dir, "wells", w["id"]))),
|
|
9991
|
+
}
|
|
9992
|
+
failed2 = [k for k, v in c2.items() if not v]
|
|
9993
|
+
ok(not failed2,
|
|
9994
|
+
"CL2 report history: a well report written twice keeps both versions, newest first, by report id, the newest identical to the report at "
|
|
9995
|
+
"its usual path, every file's SHA-256 in the index (the drawings too); the pad report and the drilling record kept the same way; a "
|
|
9996
|
+
"report written outside a workspace keeps none; a prune names what it would remove and removes nothing until applied"
|
|
9997
|
+
+ (f" [failed: {', '.join(failed2)}]" if failed2 else ""))
|
|
9998
|
+
|
|
9999
|
+
# -- CL3 the dossier ---------------------------------------------------------------------------------------------
|
|
10000
|
+
e1 = DZ.build(ws, "tester", __version__, w["id"])
|
|
10001
|
+
e2 = DZ.build(ws, "tester", __version__, None, include_sources=True)
|
|
10002
|
+
z1 = Path(ws.reports_dir, e1["path"]); z2 = Path(ws.reports_dir, e2["path"])
|
|
10003
|
+
v1 = DZ.verify(str(z1), ws)
|
|
10004
|
+
bare = d / "bare"; bare.mkdir()
|
|
10005
|
+
with zipfile.ZipFile(z1) as z:
|
|
10006
|
+
names = z.namelist(); man = json.loads(z.read("manifest.json")); z.extract("verify_dossier.py", str(bare))
|
|
10007
|
+
alone = _sp.run([sys.executable, "-I", str(bare / "verify_dossier.py"), str(z1)], capture_output=True, text=True, cwd=str(bare))
|
|
10008
|
+
alone_src = _sp.run([sys.executable, "-I", str(bare / "verify_dossier.py"), str(z1), "--sources", str(Path(wsp, "wells", w["id"], "source"))],
|
|
10009
|
+
capture_output=True, text=True, cwd=str(bare))
|
|
10010
|
+
|
|
10011
|
+
def rewrite(src, dst, change):
|
|
10012
|
+
with zipfile.ZipFile(src) as zi, zipfile.ZipFile(dst, "w", zipfile.ZIP_DEFLATED) as zo:
|
|
10013
|
+
for n in zi.namelist():
|
|
10014
|
+
b = zi.read(n)
|
|
10015
|
+
b2 = change(n, b)
|
|
10016
|
+
if b2 is not None:
|
|
10017
|
+
zo.writestr(n, b2)
|
|
10018
|
+
rep_name = next(f["path"] for f in man["files"] if f["path"].endswith("well_report.html"))
|
|
10019
|
+
rewrite(z1, d / "t_file.zip", lambda n, b: b.replace(b"SYNTHETIC", b"SYNTHETIX", 1) if n == rep_name else b)
|
|
10020
|
+
rewrite(z1, d / "t_man.zip", lambda n, b: b.replace(b'"created_by":"tester"', b'"created_by":"someone"') if n == "manifest.json" else b)
|
|
10021
|
+
rewrite(z1, d / "t_extra.zip", lambda n, b: b)
|
|
10022
|
+
with zipfile.ZipFile(d / "t_extra.zip", "a") as za:
|
|
10023
|
+
za.writestr("reports/extra.html", "<p>added</p>")
|
|
10024
|
+
rewrite(z1, d / "t_drop.zip", lambda n, b: None if n == rep_name else b)
|
|
10025
|
+
t_file, t_man, t_extra, t_drop = (DZ.verify(str(d / f"t_{k}.zip")) for k in ("file", "man", "extra", "drop"))
|
|
10026
|
+
other = Workspace.create(str(d / "ws2"), "Other", actor="tester")
|
|
10027
|
+
v_other = DZ.verify(str(z1), other)
|
|
10028
|
+
# the workspace moves on: the source record and an earlier audit line change
|
|
10029
|
+
src = next(Path(wsp, "wells", w["id"], "source").iterdir())
|
|
10030
|
+
raw = src.read_bytes()
|
|
10031
|
+
src.write_bytes(raw + b"\n")
|
|
10032
|
+
v_src = DZ.verify(str(z1), ws)
|
|
10033
|
+
src.write_bytes(raw)
|
|
10034
|
+
al = Path(ws.audit_path).read_text(encoding="utf-8").splitlines(keepends=True)
|
|
10035
|
+
Path(ws.audit_path).write_text("".join([al[0].replace("tester", "Tester", 1)] + al[1:]), encoding="utf-8")
|
|
10036
|
+
v_aud = DZ.verify(str(z1), ws)
|
|
10037
|
+
Path(ws.audit_path).write_text("".join(al), encoding="utf-8")
|
|
10038
|
+
v_back = DZ.verify(str(z1), ws)
|
|
10039
|
+
led = DZ.ledger(ws)
|
|
10040
|
+
with zipfile.ZipFile(z2) as z:
|
|
10041
|
+
man2 = json.loads(z.read("manifest.json"))
|
|
10042
|
+
ck = {c["check"]: c["ok"] for c in v_aud.get("workspace_checks", [])}
|
|
10043
|
+
c3 = {
|
|
10044
|
+
"valid": v1["status"] == "VALID" and all(c["ok"] for c in v1["workspace_checks"]) and v1["fingerprint"] == DZ.key_info(ws)["fingerprint"],
|
|
10045
|
+
"contents": {"manifest.json", "signature.json", "verify_dossier.py", "README.txt"} <= set(names) and any(n.startswith("audit/") for n in names)
|
|
10046
|
+
and any(n.startswith("declarations/wells/") for n in names) and not any(n.startswith("sources/") for n in names)
|
|
10047
|
+
and man["sources"] and man["sources"][0]["embedded"] is False and man["audit_chain"]["lines"] > 0
|
|
10048
|
+
and any(f.get("history") for f in man["files"] if f["role"] == "report") and not any("keys/" in n or "dossier_ed25519" in n for n in names),
|
|
10049
|
+
"standalone": alone.returncode == 0 and alone.stdout.startswith("VALID") and alone_src.returncode == 0 and "MATCH" in alone_src.stdout,
|
|
10050
|
+
"tamper": t_file["status"] == "INVALID" and not {c["check"]: c["ok"] for c in t_file["checks"]}["every file matches its hash"]
|
|
10051
|
+
and t_man["status"] == "INVALID" and not {c["check"]: c["ok"] for c in t_man["checks"]}["the signature verifies"]
|
|
10052
|
+
and t_extra["status"] == "INVALID" and "reports/extra.html" in {c["check"]: c["detail"] for c in t_extra["checks"]}["nothing unsigned rides along"]
|
|
10053
|
+
and t_drop["status"] == "INVALID",
|
|
10054
|
+
"other_site": v_other["status"].startswith("VALID, BUT") and not v_other["workspace_checks"][0]["ok"],
|
|
10055
|
+
"changed": v_src["status"] == "VALID, BUT THE WORKSPACE HAS CHANGED" and any(x["status"] == "DIFFERS" for x in v_src["workspace_sources"])
|
|
10056
|
+
and v_aud["status"] == "VALID, BUT THE WORKSPACE HAS CHANGED" and not ck["the audit log still holds what was chained"] and v_back["status"] == "VALID",
|
|
10057
|
+
"chain": len(led) == 2 and led[1]["previous"] == led[0]["dossier_id"] and man2["previous"]["manifest_sha256"] == led[0]["manifest_sha256"]
|
|
10058
|
+
and man2["scope"]["kind"] == "pad" and man2["sources"][0]["embedded"] and any(f["role"] == "source" for f in man2["files"])
|
|
10059
|
+
and any(a["action"] == "dossier.key.create" for a in ws.audit_log(500)) and sum(a["action"] == "dossier.sign" for a in ws.audit_log(500)) == 2,
|
|
10060
|
+
"evidence_pack_no_key": "dossier_ed25519" not in open(pkg / "files.py", encoding="utf-8").read(),
|
|
10061
|
+
}
|
|
10062
|
+
Users(str(Path(wsp, "users.json"))).add("v", "viewer-pass-1", "viewer"); Users(str(Path(wsp, "users.json"))).add("op", "op-pass-123", "operator")
|
|
10063
|
+
svc = Service(wsp, port=0, scheduler=False).start()
|
|
10064
|
+
base_url = svc.url.rstrip("/")
|
|
10065
|
+
|
|
10066
|
+
def opener(name, pw_):
|
|
10067
|
+
o = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))
|
|
10068
|
+
rq = urllib.request.Request(base_url + "/api/login", method="POST", data=json.dumps({"name": name, "password": pw_}).encode())
|
|
10069
|
+
rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1"); o.open(rq, timeout=30)
|
|
10070
|
+
return o
|
|
10071
|
+
|
|
10072
|
+
def call(o, method, path, body=None, raw=False):
|
|
10073
|
+
rq = urllib.request.Request(base_url + path, method=method, data=(json.dumps(body).encode() if body is not None else None))
|
|
10074
|
+
if method == "POST":
|
|
10075
|
+
rq.add_header("Content-Type", "application/json"); rq.add_header("X-GEA-Action", "1")
|
|
10076
|
+
try:
|
|
10077
|
+
with o.open(rq, timeout=120) as rr_:
|
|
10078
|
+
b = rr_.read()
|
|
10079
|
+
return rr_.status, (b if raw else json.loads(b))
|
|
10080
|
+
except urllib.error.HTTPError as e:
|
|
10081
|
+
return e.code, (None if raw else json.loads(e.read()))
|
|
10082
|
+
try:
|
|
10083
|
+
V, O = opener("v", "viewer-pass-1"), opener("op", "op-pass-123")
|
|
10084
|
+
s_g, gj = call(V, "GET", "/api/dossier")
|
|
10085
|
+
s_vs, _ = call(V, "POST", "/api/dossier/sign", {"well_id": w["id"]})
|
|
10086
|
+
s_os, oj = call(O, "POST", "/api/dossier/sign", {"well_id": w["id"]})
|
|
10087
|
+
s_vv, vj = call(V, "POST", "/api/dossier/verify", {"path": e1["path"]})
|
|
10088
|
+
s_up, uj = call(V, "POST", "/api/dossier/verify", {"filename": "t.zip", "content_b64": _b64.b64encode((d / "t_file.zip").read_bytes()).decode()})
|
|
10089
|
+
s_bad, _ = call(V, "POST", "/api/dossier/verify", {"path": "../keys/dossier_ed25519.json"})
|
|
10090
|
+
s_nw, _ = call(O, "POST", "/api/dossier/sign", {"well_id": "nope"})
|
|
10091
|
+
s_dl, zb = call(V, "GET", "/reports/" + e1["path"], raw=True)
|
|
10092
|
+
s_hv, hb = call(V, "GET", "/reports/" + vs[0]["dir"] + "/well_report.html", raw=True)
|
|
10093
|
+
finally:
|
|
10094
|
+
svc.stop()
|
|
10095
|
+
cli_k = _sp.run([sys.executable, "-m", "gea", "dossier", "--workspace", wsp, "--key"], capture_output=True, text=True, cwd=str(pkg.parent))
|
|
10096
|
+
cli_s = _sp.run([sys.executable, "-m", "gea", "dossier", "--workspace", wsp], capture_output=True, text=True, cwd=str(pkg.parent))
|
|
10097
|
+
cli_v = _sp.run([sys.executable, "-m", "gea", "dossier", "--verify", str(d / "t_man.zip")], capture_output=True, text=True, cwd=str(pkg.parent))
|
|
10098
|
+
cli_h = _sp.run([sys.executable, "-m", "gea", "reports-history", "--workspace", wsp, "--family", fam], capture_output=True, text=True, cwd=str(pkg.parent))
|
|
10099
|
+
page_src = (pkg / "web" / "app.html").read_text(encoding="utf-8")
|
|
10100
|
+
c3.update({
|
|
10101
|
+
"api": s_g == 200 and gj["key"]["fingerprint"] == DZ.key_info(ws)["fingerprint"] and len(gj["dossiers"]) == 2 and gj["history"]["n_versions"] >= 3
|
|
10102
|
+
and s_vs == 403 and s_os == 200 and oj["previous"] == e2["dossier_id"] and s_vv == 200 and vj["status"] == "VALID" and s_up == 200 and uj["status"] == "INVALID"
|
|
10103
|
+
and s_bad == 400 and s_nw == 404 and s_dl == 200 and zb[:2] == b"PK" and s_hv == 200 and hb == newest,
|
|
10104
|
+
"cli": cli_k.returncode == 0 and DZ.key_info(ws)["fingerprint"] in cli_k.stdout and cli_s.returncode == 0 and "signed " in cli_s.stdout
|
|
10105
|
+
and cli_v.returncode == 1 and "the signature verifies" in cli_v.stdout and cli_h.returncode == 0 and r2["report_id"] in cli_h.stdout,
|
|
10106
|
+
"page": all(x in page_src for x in ("rpCards", "Signed dossiers", "/api/dossier/sign", "/api/dossier/verify", "Report history", "Check a dossier someone sent you")),
|
|
10107
|
+
"help": all(any(t[0] == k for t in H.INDEX) and not H.check(k) for k in ("report-history", "dossier")),
|
|
10108
|
+
})
|
|
10109
|
+
failed3 = [k for k, v in c3.items() if not v]
|
|
10110
|
+
ok(not failed3,
|
|
10111
|
+
"CL3 the signed dossier: a well's reports, declarations, audit log and source hashes signed with a key made on first use; its own "
|
|
10112
|
+
"checker run alone in a bare Python says VALID and matches the source record; a changed report, a changed manifest, a file added and "
|
|
10113
|
+
"a file removed each INVALID, naming the check; another site's workspace, a changed source record and a rewritten early audit line "
|
|
10114
|
+
"each VALID BUT THE WORKSPACE HAS CHANGED, and VALID again once restored; the pad's dossier with the sources embedded chained to the "
|
|
10115
|
+
"well's; the key never in a dossier; the API, the CLI, the Reports tab and the help pages"
|
|
10116
|
+
+ (f" [failed: {', '.join(failed3)}]" if failed3 else ""))
|
|
10117
|
+
|
|
10118
|
+
|
|
9913
10119
|
def main() -> int:
|
|
9914
10120
|
print("GEA-Program - ACCEPTANCE SUITE (the product gate)")
|
|
9915
10121
|
# a handle a job subprocess still holds at the end must not turn a finished gate into a traceback on Windows:
|
|
@@ -10002,6 +10208,7 @@ def main() -> int:
|
|
|
10002
10208
|
section_ci_drill_string(tmp)
|
|
10003
10209
|
section_cj_declarations(tmp)
|
|
10004
10210
|
section_ck_operations_seismicity(tmp)
|
|
10211
|
+
section_cl_history_and_dossier(tmp)
|
|
10005
10212
|
if _FAILS:
|
|
10006
10213
|
print(f"[ACCEPTANCE] {len(_FAILS)} FAILURES ({_PASS} passed):")
|
|
10007
10214
|
for f in _FAILS:
|
|
@@ -1925,4 +1925,9 @@ def write(doc: Document, out_dir: str, basename: str = 'gauge_drift_report') ->
|
|
|
1925
1925
|
write_catalogue_csv(doc.data['_catalogue_obj'], paths['catalogue_csv'])
|
|
1926
1926
|
else:
|
|
1927
1927
|
paths.pop('catalogue_csv')
|
|
1928
|
+
try: # inside a workspace, keep the version this one replaces
|
|
1929
|
+
from . import report_history as _RH
|
|
1930
|
+
_RH.record(out_dir, basename, paths, getattr(doc, 'report_id', ''), getattr(doc, 'title', ''))
|
|
1931
|
+
except OSError:
|
|
1932
|
+
pass # a full disk loses the copy, never the report
|
|
1928
1933
|
return paths
|