openc3 7.3.0 → 7.4.0
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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Guardfile +0 -0
- data/LICENSE.md +0 -0
- data/README.md +0 -0
- data/Rakefile +0 -0
- data/bin/openc3cli +138 -0
- data/bin/pipuninstall +0 -0
- data/bin/uvinstall +10 -3
- data/data/config/_array_params.yaml +0 -0
- data/data/config/_canvas_values.yaml +0 -0
- data/data/config/_graph_params.yaml +0 -0
- data/data/config/_id_items.yaml +0 -0
- data/data/config/_id_params.yaml +0 -0
- data/data/config/_interfaces.yaml +0 -0
- data/data/config/_items.yaml +0 -0
- data/data/config/_params.yaml +0 -0
- data/data/config/command.yaml +0 -0
- data/data/config/command_modifiers.yaml +2 -0
- data/data/config/command_telemetry.yaml +0 -0
- data/data/config/conversions.yaml +0 -0
- data/data/config/graph_settings.yaml +0 -0
- data/data/config/interface_modifiers.yaml +103 -1
- data/data/config/item_modifiers.yaml +0 -0
- data/data/config/microservice.yaml +5 -2
- data/data/config/param_item_modifiers.yaml +0 -0
- data/data/config/parameter_modifiers.yaml +0 -0
- data/data/config/plugins.yaml +0 -0
- data/data/config/processors.yaml +0 -0
- data/data/config/protocols.yaml +0 -0
- data/data/config/screen.yaml +0 -0
- data/data/config/settings.yaml +0 -0
- data/data/config/table_manager.yaml +0 -0
- data/data/config/table_parameter_modifiers.yaml +0 -0
- data/data/config/target.yaml +0 -0
- data/data/config/target_config.yaml +0 -0
- data/data/config/telemetry.yaml +0 -0
- data/data/config/telemetry_modifiers.yaml +2 -0
- data/data/config/tool.yaml +0 -0
- data/data/config/unknown.yaml +0 -0
- data/data/config/widgets.yaml +6 -0
- data/data/xtce_schemas/SpaceSystem_20180204.xsd +0 -0
- data/data/xtce_schemas/xml.xsd +0 -0
- data/ext/openc3/ext/array/array.c +0 -0
- data/ext/openc3/ext/array/extconf.rb +0 -0
- data/ext/openc3/ext/buffered_file/buffered_file.c +0 -0
- data/ext/openc3/ext/buffered_file/extconf.rb +0 -0
- data/ext/openc3/ext/burst_protocol/burst_protocol.c +6 -0
- data/ext/openc3/ext/burst_protocol/extconf.rb +0 -0
- data/ext/openc3/ext/config_parser/config_parser.c +0 -0
- data/ext/openc3/ext/config_parser/extconf.rb +0 -0
- data/ext/openc3/ext/crc/crc.c +0 -0
- data/ext/openc3/ext/crc/extconf.rb +0 -0
- data/ext/openc3/ext/openc3_io/extconf.rb +0 -0
- data/ext/openc3/ext/openc3_io/openc3_io.c +0 -0
- data/ext/openc3/ext/packet/extconf.rb +0 -0
- data/ext/openc3/ext/packet/packet.c +0 -0
- data/ext/openc3/ext/platform/extconf.rb +0 -0
- data/ext/openc3/ext/platform/platform.c +4 -1
- data/ext/openc3/ext/polynomial_conversion/extconf.rb +0 -0
- data/ext/openc3/ext/polynomial_conversion/polynomial_conversion.c +0 -0
- data/ext/openc3/ext/string/extconf.rb +0 -0
- data/ext/openc3/ext/string/string.c +0 -0
- data/ext/openc3/ext/structure/structure.c +49 -17
- data/ext/openc3/ext/tabbed_plots_config/extconf.rb +0 -0
- data/ext/openc3/ext/tabbed_plots_config/tabbed_plots_config.c +0 -0
- data/ext/openc3/ext/telemetry/extconf.rb +0 -0
- data/ext/openc3/ext/telemetry/telemetry.c +0 -0
- data/lib/cosmos.rb +0 -0
- data/lib/cosmosc2.rb +0 -0
- data/lib/openc3/accessors/accessor.rb +0 -0
- data/lib/openc3/accessors/binary_accessor.rb +63 -9
- data/lib/openc3/accessors/cbor_accessor.rb +0 -0
- data/lib/openc3/accessors/form_accessor.rb +0 -0
- data/lib/openc3/accessors/html_accessor.rb +0 -0
- data/lib/openc3/accessors/http_accessor.rb +0 -0
- data/lib/openc3/accessors/json_accessor.rb +0 -0
- data/lib/openc3/accessors/template_accessor.rb +0 -0
- data/lib/openc3/accessors/xml_accessor.rb +0 -0
- data/lib/openc3/accessors.rb +0 -0
- data/lib/openc3/api/README.md +0 -0
- data/lib/openc3/api/api.rb +0 -0
- data/lib/openc3/api/authorized_api.rb +0 -0
- data/lib/openc3/api/calendar_api.rb +0 -0
- data/lib/openc3/api/cmd_api.rb +1 -1
- data/lib/openc3/api/config_api.rb +0 -0
- data/lib/openc3/api/interface_api.rb +0 -0
- data/lib/openc3/api/limits_api.rb +0 -0
- data/lib/openc3/api/metrics_api.rb +1 -1
- data/lib/openc3/api/offline_access_api.rb +1 -1
- data/lib/openc3/api/router_api.rb +0 -0
- data/lib/openc3/api/settings_api.rb +22 -18
- data/lib/openc3/api/stash_api.rb +1 -1
- data/lib/openc3/api/target_api.rb +0 -0
- data/lib/openc3/api/tlm_api.rb +4 -3
- data/lib/openc3/bridge/bridge.rb +0 -0
- data/lib/openc3/bridge/bridge_config.rb +0 -0
- data/lib/openc3/bridge/bridge_interface_thread.rb +0 -0
- data/lib/openc3/bridge/bridge_router_thread.rb +0 -0
- data/lib/openc3/ccsds/ccsds_packet.rb +0 -0
- data/lib/openc3/ccsds/ccsds_parser.rb +0 -0
- data/lib/openc3/config/config_parser.rb +78 -17
- data/lib/openc3/config/meta_config_parser.rb +0 -0
- data/lib/openc3/conversions/bit_reverse_conversion.rb +0 -0
- data/lib/openc3/conversions/conversion.rb +0 -0
- data/lib/openc3/conversions/generic_conversion.rb +0 -0
- data/lib/openc3/conversions/ip_read_conversion.rb +0 -0
- data/lib/openc3/conversions/ip_write_conversion.rb +0 -0
- data/lib/openc3/conversions/object_read_conversion.rb +0 -0
- data/lib/openc3/conversions/object_write_conversion.rb +0 -0
- data/lib/openc3/conversions/packet_time_formatted_conversion.rb +0 -0
- data/lib/openc3/conversions/packet_time_seconds_conversion.rb +0 -0
- data/lib/openc3/conversions/polynomial_conversion.rb +0 -0
- data/lib/openc3/conversions/processor_conversion.rb +0 -0
- data/lib/openc3/conversions/received_count_conversion.rb +0 -0
- data/lib/openc3/conversions/received_time_formatted_conversion.rb +0 -0
- data/lib/openc3/conversions/received_time_seconds_conversion.rb +0 -0
- data/lib/openc3/conversions/segmented_polynomial_conversion.rb +0 -0
- data/lib/openc3/conversions/unix_time_conversion.rb +0 -0
- data/lib/openc3/conversions/unix_time_formatted_conversion.rb +0 -0
- data/lib/openc3/conversions/unix_time_seconds_conversion.rb +0 -0
- data/lib/openc3/conversions.rb +0 -0
- data/lib/openc3/core_ext/array.rb +0 -0
- data/lib/openc3/core_ext/binding.rb +0 -0
- data/lib/openc3/core_ext/class.rb +0 -0
- data/lib/openc3/core_ext/exception.rb +0 -0
- data/lib/openc3/core_ext/faraday.rb +0 -0
- data/lib/openc3/core_ext/file.rb +0 -0
- data/lib/openc3/core_ext/io.rb +0 -0
- data/lib/openc3/core_ext/kernel.rb +0 -0
- data/lib/openc3/core_ext/math.rb +0 -0
- data/lib/openc3/core_ext/matrix.rb +0 -0
- data/lib/openc3/core_ext/objectspace.rb +0 -0
- data/lib/openc3/core_ext/openc3_io.rb +0 -0
- data/lib/openc3/core_ext/range.rb +0 -0
- data/lib/openc3/core_ext/socket.rb +0 -0
- data/lib/openc3/core_ext/string.rb +0 -0
- data/lib/openc3/core_ext/stringio.rb +0 -0
- data/lib/openc3/core_ext/tempfile.rb +0 -0
- data/lib/openc3/core_ext/time.rb +0 -0
- data/lib/openc3/core_ext.rb +0 -0
- data/lib/openc3/ext/.keep +0 -0
- data/lib/openc3/interfaces/file_interface.rb +0 -0
- data/lib/openc3/interfaces/http_client_interface.rb +0 -0
- data/lib/openc3/interfaces/http_server_interface.rb +0 -0
- data/lib/openc3/interfaces/interface.rb +5 -4
- data/lib/openc3/interfaces/mqtt_interface.rb +0 -0
- data/lib/openc3/interfaces/mqtt_stream_interface.rb +2 -0
- data/lib/openc3/interfaces/protocols/burst_protocol.rb +27 -0
- data/lib/openc3/interfaces/protocols/cmd_response_protocol.rb +0 -0
- data/lib/openc3/interfaces/protocols/cobs_protocol.rb +0 -0
- data/lib/openc3/interfaces/protocols/crc_protocol.rb +0 -0
- data/lib/openc3/interfaces/protocols/fixed_protocol.rb +0 -0
- data/lib/openc3/interfaces/protocols/ignore_packet_protocol.rb +0 -0
- data/lib/openc3/interfaces/protocols/length_protocol.rb +7 -0
- data/lib/openc3/interfaces/protocols/preidentified_protocol.rb +7 -0
- data/lib/openc3/interfaces/protocols/protocol.rb +4 -4
- data/lib/openc3/interfaces/protocols/slip_protocol.rb +0 -0
- data/lib/openc3/interfaces/protocols/template_protocol.rb +2 -2
- data/lib/openc3/interfaces/protocols/terminated_protocol.rb +0 -0
- data/lib/openc3/interfaces/serial_interface.rb +2 -0
- data/lib/openc3/interfaces/simulated_target_interface.rb +0 -0
- data/lib/openc3/interfaces/stream_interface.rb +0 -0
- data/lib/openc3/interfaces/tcpip_client_interface.rb +2 -0
- data/lib/openc3/interfaces/tcpip_server_interface.rb +0 -0
- data/lib/openc3/interfaces/udp_interface.rb +16 -5
- data/lib/openc3/interfaces.rb +0 -0
- data/lib/openc3/io/buffered_file.rb +0 -0
- data/lib/openc3/io/io_multiplexer.rb +0 -0
- data/lib/openc3/io/json_api.rb +3 -2
- data/lib/openc3/io/json_api_object.rb +0 -0
- data/lib/openc3/io/json_drb.rb +20 -4
- data/lib/openc3/io/json_drb_object.rb +0 -0
- data/lib/openc3/io/json_drb_rack.rb +0 -0
- data/lib/openc3/io/json_rpc.rb +0 -0
- data/lib/openc3/io/posix_serial_driver.rb +0 -0
- data/lib/openc3/io/serial_driver.rb +0 -0
- data/lib/openc3/io/stderr.rb +0 -0
- data/lib/openc3/io/stdout.rb +0 -0
- data/lib/openc3/io/udp_sockets.rb +38 -8
- data/lib/openc3/io/win32_serial_driver.rb +1 -0
- data/lib/openc3/logs/buffered_packet_log_reader.rb +0 -0
- data/lib/openc3/logs/buffered_packet_log_writer.rb +0 -0
- data/lib/openc3/logs/log_writer.rb +0 -0
- data/lib/openc3/logs/packet_log_constants.rb +0 -0
- data/lib/openc3/logs/packet_log_reader.rb +23 -2
- data/lib/openc3/logs/packet_log_writer.rb +5 -0
- data/lib/openc3/logs/stream_log.rb +1 -1
- data/lib/openc3/logs/stream_log_pair.rb +0 -0
- data/lib/openc3/logs/text_log_writer.rb +0 -0
- data/lib/openc3/logs.rb +0 -0
- data/lib/openc3/microservices/cleanup_microservice.rb +0 -0
- data/lib/openc3/microservices/decom_common.rb +0 -0
- data/lib/openc3/microservices/decom_microservice.rb +0 -0
- data/lib/openc3/microservices/interface_decom_common.rb +2 -1
- data/lib/openc3/microservices/interface_microservice.rb +72 -25
- data/lib/openc3/microservices/log_microservice.rb +0 -0
- data/lib/openc3/microservices/microservice.rb +3 -3
- data/lib/openc3/microservices/multi_microservice.rb +1 -1
- data/lib/openc3/microservices/periodic_microservice.rb +2 -2
- data/lib/openc3/microservices/plugin_microservice.rb +0 -0
- data/lib/openc3/microservices/queue_microservice.rb +0 -0
- data/lib/openc3/microservices/router_microservice.rb +0 -0
- data/lib/openc3/microservices/scope_cleanup_microservice.rb +0 -0
- data/lib/openc3/microservices/text_log_microservice.rb +0 -0
- data/lib/openc3/migrations/20220420190000_log_stuff.rb +0 -0
- data/lib/openc3/migrations/20221202214600_add_target_names.rb +0 -0
- data/lib/openc3/migrations/20221210174900_convert_to_multi.rb +0 -0
- data/lib/openc3/migrations/20230915000002_no_scope_log_messages.rb +0 -0
- data/lib/openc3/migrations/20231022000000_tlm_viewer_config.rb +0 -0
- data/lib/openc3/migrations/20241208080000_no_critical_cmd.rb +0 -0
- data/lib/openc3/migrations/20241208080001_no_trigger_group.rb +0 -0
- data/lib/openc3/migrations/20250108060000_news_feed.rb +0 -0
- data/lib/openc3/migrations/20250402000000_periodic_only_default.rb +0 -0
- data/lib/openc3/migrations/20260203000000_remove_store_id.rb +0 -0
- data/lib/openc3/migrations/20260204000000_remove_decom_reducer.rb +0 -0
- data/lib/openc3/migrations/20260701000000_updated_at_to_int.rb +0 -0
- data/lib/openc3/migrations/20260704000000_default_bridge.rb +38 -0
- data/lib/openc3/migrations/20260731000000_system_health_json.rb +11 -0
- data/lib/openc3/models/activity_model.rb +0 -0
- data/lib/openc3/models/auth_model.rb +35 -7
- data/lib/openc3/models/bridge_model.rb +133 -0
- data/lib/openc3/models/config_keyword_model.rb +63 -0
- data/lib/openc3/models/cvt_model.rb +0 -0
- data/lib/openc3/models/db_sharded_model.rb +0 -0
- data/lib/openc3/models/environment_model.rb +0 -0
- data/lib/openc3/models/gem_model.rb +12 -9
- data/lib/openc3/models/host_interface_microservice_model.rb +114 -0
- data/lib/openc3/models/info_model.rb +0 -0
- data/lib/openc3/models/interface_model.rb +178 -19
- data/lib/openc3/models/interface_status_model.rb +0 -0
- data/lib/openc3/models/metadata_model.rb +0 -0
- data/lib/openc3/models/metric_model.rb +0 -0
- data/lib/openc3/models/microservice_model.rb +9 -22
- data/lib/openc3/models/microservice_status_model.rb +0 -0
- data/lib/openc3/models/migration_model.rb +0 -0
- data/lib/openc3/models/model.rb +0 -0
- data/lib/openc3/models/news_model.rb +0 -0
- data/lib/openc3/models/note_model.rb +0 -0
- data/lib/openc3/models/offline_access_model.rb +0 -0
- data/lib/openc3/models/ping_model.rb +0 -0
- data/lib/openc3/models/plugin_model.rb +9 -2
- data/lib/openc3/models/plugin_store_model.rb +0 -0
- data/lib/openc3/models/process_status_model.rb +0 -0
- data/lib/openc3/models/python_package_model.rb +4 -4
- data/lib/openc3/models/queue_model.rb +0 -0
- data/lib/openc3/models/reaction_model.rb +0 -0
- data/lib/openc3/models/reingest_job_model.rb +0 -0
- data/lib/openc3/models/router_model.rb +0 -0
- data/lib/openc3/models/router_status_model.rb +0 -0
- data/lib/openc3/models/scope_model.rb +51 -26
- data/lib/openc3/models/script_engine_model.rb +0 -0
- data/lib/openc3/models/script_status_model.rb +0 -0
- data/lib/openc3/models/secret_model.rb +0 -0
- data/lib/openc3/models/setting_model.rb +546 -3
- data/lib/openc3/models/sorted_model.rb +0 -0
- data/lib/openc3/models/stash_model.rb +0 -0
- data/lib/openc3/models/target_model.rb +30 -25
- data/lib/openc3/models/timeline_model.rb +0 -0
- data/lib/openc3/models/tool_config_model.rb +0 -0
- data/lib/openc3/models/tool_model.rb +1 -0
- data/lib/openc3/models/trigger_group_model.rb +0 -0
- data/lib/openc3/models/trigger_model.rb +20 -0
- data/lib/openc3/models/widget_model.rb +0 -0
- data/lib/openc3/operators/microservice_operator.rb +64 -22
- data/lib/openc3/operators/operator.rb +4 -4
- data/lib/openc3/packets/binary_accessor.rb +0 -0
- data/lib/openc3/packets/command_validator.rb +0 -0
- data/lib/openc3/packets/commands.rb +0 -0
- data/lib/openc3/packets/json_packet.rb +0 -0
- data/lib/openc3/packets/limits.rb +0 -0
- data/lib/openc3/packets/limits_response.rb +0 -0
- data/lib/openc3/packets/packet.rb +4 -0
- data/lib/openc3/packets/packet_config.rb +0 -0
- data/lib/openc3/packets/packet_item.rb +0 -0
- data/lib/openc3/packets/packet_item_limits.rb +0 -0
- data/lib/openc3/packets/parsers/format_string_parser.rb +0 -0
- data/lib/openc3/packets/parsers/limits_parser.rb +0 -0
- data/lib/openc3/packets/parsers/limits_response_parser.rb +0 -0
- data/lib/openc3/packets/parsers/packet_item_parser.rb +0 -0
- data/lib/openc3/packets/parsers/packet_parser.rb +0 -0
- data/lib/openc3/packets/parsers/processor_parser.rb +0 -0
- data/lib/openc3/packets/parsers/state_parser.rb +0 -0
- data/lib/openc3/packets/parsers/xtce_converter.rb +0 -0
- data/lib/openc3/packets/parsers/xtce_parser.rb +0 -0
- data/lib/openc3/packets/structure.rb +7 -1
- data/lib/openc3/packets/structure_item.rb +0 -0
- data/lib/openc3/packets/telemetry.rb +0 -0
- data/lib/openc3/processors/processor.rb +2 -0
- data/lib/openc3/processors/statistics_processor.rb +0 -0
- data/lib/openc3/processors/watermark_processor.rb +0 -0
- data/lib/openc3/processors.rb +0 -0
- data/lib/openc3/script/api_shared.rb +0 -0
- data/lib/openc3/script/autonomic.rb +12 -12
- data/lib/openc3/script/calendar.rb +0 -0
- data/lib/openc3/script/commands.rb +0 -0
- data/lib/openc3/script/critical_cmd.rb +0 -0
- data/lib/openc3/script/exceptions.rb +0 -0
- data/lib/openc3/script/extract.rb +0 -0
- data/lib/openc3/script/limits.rb +0 -0
- data/lib/openc3/script/metadata.rb +0 -0
- data/lib/openc3/script/packages.rb +0 -0
- data/lib/openc3/script/plugins.rb +0 -0
- data/lib/openc3/script/queue.rb +0 -0
- data/lib/openc3/script/screen.rb +0 -0
- data/lib/openc3/script/script.rb +2 -2
- data/lib/openc3/script/script_runner.rb +0 -0
- data/lib/openc3/script/storage.rb +4 -4
- data/lib/openc3/script/suite.rb +0 -0
- data/lib/openc3/script/suite_results.rb +0 -0
- data/lib/openc3/script/suite_runner.rb +26 -0
- data/lib/openc3/script/tables.rb +0 -0
- data/lib/openc3/script/telemetry.rb +9 -3
- data/lib/openc3/script/web_socket_api.rb +218 -145
- data/lib/openc3/script.rb +0 -0
- data/lib/openc3/script_engines/script_engine.rb +0 -0
- data/lib/openc3/streams/mqtt_stream.rb +0 -0
- data/lib/openc3/streams/serial_stream.rb +0 -0
- data/lib/openc3/streams/stream.rb +0 -0
- data/lib/openc3/streams/tcpip_client_stream.rb +0 -0
- data/lib/openc3/streams/tcpip_socket_stream.rb +0 -0
- data/lib/openc3/streams/web_socket_client_stream.rb +0 -0
- data/lib/openc3/subpacketizers/subpacketizer.rb +0 -0
- data/lib/openc3/system/system.rb +0 -0
- data/lib/openc3/system/target.rb +0 -0
- data/lib/openc3/system.rb +0 -0
- data/lib/openc3/tools/cmd_tlm_server/api.rb +0 -0
- data/lib/openc3/tools/cmd_tlm_server/interface_thread.rb +7 -0
- data/lib/openc3/tools/table_manager/table.rb +0 -0
- data/lib/openc3/tools/table_manager/table_config.rb +0 -0
- data/lib/openc3/tools/table_manager/table_item.rb +0 -0
- data/lib/openc3/tools/table_manager/table_item_parser.rb +0 -0
- data/lib/openc3/tools/table_manager/table_manager_core.rb +0 -0
- data/lib/openc3/tools/table_manager/table_parser.rb +0 -0
- data/lib/openc3/tools/test_runner/test.rb +0 -0
- data/lib/openc3/top_level.rb +1 -1
- data/lib/openc3/topics/autonomic_topic.rb +0 -0
- data/lib/openc3/topics/calendar_topic.rb +0 -0
- data/lib/openc3/topics/command_decom_topic.rb +0 -0
- data/lib/openc3/topics/command_topic.rb +0 -0
- data/lib/openc3/topics/config_topic.rb +0 -0
- data/lib/openc3/topics/decom_interface_topic.rb +2 -1
- data/lib/openc3/topics/interface_topic.rb +8 -2
- data/lib/openc3/topics/limits_event_topic.rb +0 -0
- data/lib/openc3/topics/notebook_topic.rb +0 -0
- data/lib/openc3/topics/queue_topic.rb +0 -0
- data/lib/openc3/topics/router_topic.rb +6 -1
- data/lib/openc3/topics/system_events_topic.rb +0 -0
- data/lib/openc3/topics/telemetry_decom_topic.rb +0 -0
- data/lib/openc3/topics/telemetry_topic.rb +0 -0
- data/lib/openc3/topics/timeline_topic.rb +0 -0
- data/lib/openc3/topics/topic.rb +0 -0
- data/lib/openc3/utilities/authentication.rb +4 -4
- data/lib/openc3/utilities/authorization.rb +0 -0
- data/lib/openc3/utilities/aws_bucket.rb +2 -2
- data/lib/openc3/utilities/bucket.rb +1 -1
- data/lib/openc3/utilities/bucket_file_cache.rb +55 -22
- data/lib/openc3/utilities/bucket_require.rb +0 -0
- data/lib/openc3/utilities/bucket_utilities.rb +3 -4
- data/lib/openc3/utilities/cli_generator.rb +0 -0
- data/lib/openc3/utilities/cmd_log.rb +0 -0
- data/lib/openc3/utilities/config_overlay.rb +75 -0
- data/lib/openc3/utilities/cosmos_rails_formatter.rb +0 -0
- data/lib/openc3/utilities/crc.rb +59 -32
- data/lib/openc3/utilities/csv.rb +0 -0
- data/lib/openc3/utilities/ctrf.rb +0 -0
- data/lib/openc3/utilities/env_helper.rb +0 -0
- data/lib/openc3/utilities/local_bucket.rb +0 -0
- data/lib/openc3/utilities/local_mode.rb +32 -6
- data/lib/openc3/utilities/logger.rb +30 -8
- data/lib/openc3/utilities/message_log.rb +0 -0
- data/lib/openc3/utilities/metric.rb +0 -0
- data/lib/openc3/utilities/migration.rb +0 -0
- data/lib/openc3/utilities/open_telemetry.rb +0 -0
- data/lib/openc3/utilities/process_manager.rb +0 -0
- data/lib/openc3/utilities/pypi_url.rb +0 -0
- data/lib/openc3/utilities/python_proxy.rb +0 -0
- data/lib/openc3/utilities/python_venv.rb +135 -0
- data/lib/openc3/utilities/quaternion.rb +0 -0
- data/lib/openc3/utilities/questdb_client.rb +0 -0
- data/lib/openc3/utilities/redis_secrets.rb +0 -0
- data/lib/openc3/utilities/reingest_job.rb +0 -0
- data/lib/openc3/utilities/ruby_lex_utils.rb +0 -0
- data/lib/openc3/utilities/rubygems_url.rb +39 -0
- data/lib/openc3/utilities/running_script.rb +24 -55
- data/lib/openc3/utilities/s3_autoload.rb +5 -5
- data/lib/openc3/utilities/script.rb +12 -8
- data/lib/openc3/utilities/secrets.rb +48 -3
- data/lib/openc3/utilities/simulated_target.rb +0 -0
- data/lib/openc3/utilities/sleeper.rb +0 -0
- data/lib/openc3/utilities/store.rb +0 -0
- data/lib/openc3/utilities/store_autoload.rb +2 -2
- data/lib/openc3/utilities/store_queued.rb +0 -0
- data/lib/openc3/utilities/target_file.rb +18 -1
- data/lib/openc3/utilities/thread_manager.rb +0 -0
- data/lib/openc3/utilities/throttle.rb +0 -0
- data/lib/openc3/utilities/zip.rb +0 -0
- data/lib/openc3/utilities.rb +0 -0
- data/lib/openc3/version.rb +5 -5
- data/lib/openc3/win32/excel.rb +0 -0
- data/lib/openc3/win32/win32.rb +0 -0
- data/lib/openc3/win32/win32_main.rb +0 -0
- data/lib/openc3.rb +2 -2
- data/tasks/gemfile_stats.rake +0 -0
- data/tasks/spec.rake +0 -0
- data/templates/command_validator/command_validator.py +0 -0
- data/templates/command_validator/command_validator.rb +0 -0
- data/templates/conversion/conversion.py +0 -0
- data/templates/conversion/conversion.rb +0 -0
- data/templates/limits_response/response.py +0 -0
- data/templates/limits_response/response.rb +0 -0
- data/templates/microservice/microservices/TEMPLATE/microservice.py +0 -0
- data/templates/microservice/microservices/TEMPLATE/microservice.rb +0 -0
- data/templates/plugin/.gitignore +0 -0
- data/templates/plugin/LICENSE.md +0 -0
- data/templates/plugin/README.md +0 -0
- data/templates/plugin/Rakefile +0 -0
- data/templates/plugin/plugin.gemspec +0 -0
- data/templates/plugin/plugin.txt +0 -0
- data/templates/processor/processor.py +1 -1
- data/templates/processor/processor.rb +0 -0
- data/templates/target/targets/TARGET/cmd_tlm/cmd.txt +0 -0
- data/templates/target/targets/TARGET/cmd_tlm/tlm.txt +0 -0
- data/templates/target/targets/TARGET/lib/target.py +0 -0
- data/templates/target/targets/TARGET/lib/target.rb +0 -0
- data/templates/target/targets/TARGET/procedures/procedure.py +0 -0
- data/templates/target/targets/TARGET/procedures/procedure.rb +0 -0
- data/templates/target/targets/TARGET/public/README.txt +0 -0
- data/templates/target/targets/TARGET/screens/status.txt +0 -0
- data/templates/target/targets/TARGET/target.txt +0 -0
- data/templates/tool_angular/.editorconfig +0 -0
- data/templates/tool_angular/.gitignore +0 -0
- data/templates/tool_angular/.vscode/extensions.json +0 -0
- data/templates/tool_angular/.vscode/launch.json +0 -0
- data/templates/tool_angular/.vscode/tasks.json +0 -0
- data/templates/tool_angular/angular.json +0 -0
- data/templates/tool_angular/extra-webpack.config.js +0 -0
- data/templates/tool_angular/package.json +2 -2
- data/templates/tool_angular/src/app/app-routing.module.ts +0 -0
- data/templates/tool_angular/src/app/app.component.html +0 -0
- data/templates/tool_angular/src/app/app.component.scss +0 -0
- data/templates/tool_angular/src/app/app.component.spec.ts +0 -0
- data/templates/tool_angular/src/app/app.component.ts +0 -0
- data/templates/tool_angular/src/app/app.module.ts +0 -0
- data/templates/tool_angular/src/app/custom-overlay-container.ts +0 -0
- data/templates/tool_angular/src/app/empty-route/empty-route.component.ts +0 -0
- data/templates/tool_angular/src/app/openc3-api.d.ts +0 -0
- data/templates/tool_angular/src/assets/.gitkeep +0 -0
- data/templates/tool_angular/src/environments/environment.prod.ts +0 -0
- data/templates/tool_angular/src/environments/environment.ts +0 -0
- data/templates/tool_angular/src/favicon.ico +0 -0
- data/templates/tool_angular/src/index.html +0 -0
- data/templates/tool_angular/src/main.single-spa.ts +0 -0
- data/templates/tool_angular/src/single-spa/asset-url.ts +0 -0
- data/templates/tool_angular/src/single-spa/single-spa-props.ts +0 -0
- data/templates/tool_angular/src/styles.scss +0 -0
- data/templates/tool_angular/tsconfig.app.json +0 -0
- data/templates/tool_angular/tsconfig.json +0 -0
- data/templates/tool_angular/tsconfig.spec.json +0 -0
- data/templates/tool_react/.eslintrc +0 -0
- data/templates/tool_react/.gitignore +0 -0
- data/templates/tool_react/.prettierignore +0 -0
- data/templates/tool_react/babel.config.json +0 -0
- data/templates/tool_react/jest.config.js +0 -0
- data/templates/tool_react/package.json +1 -1
- data/templates/tool_react/src/openc3-tool_name.js +0 -0
- data/templates/tool_react/src/root.component.js +0 -0
- data/templates/tool_react/src/root.component.test.js +0 -0
- data/templates/tool_react/webpack.config.js +0 -0
- data/templates/tool_svelte/.gitignore +0 -0
- data/templates/tool_svelte/.prettierignore +0 -0
- data/templates/tool_svelte/.prettierrc.js +0 -0
- data/templates/tool_svelte/babel.config.js +0 -0
- data/templates/tool_svelte/build/smui.css +0 -0
- data/templates/tool_svelte/jest.config.js +0 -0
- data/templates/tool_svelte/package.json +1 -1
- data/templates/tool_svelte/rollup.config.js +0 -0
- data/templates/tool_svelte/src/App.svelte +0 -0
- data/templates/tool_svelte/src/App.test.js +0 -0
- data/templates/tool_svelte/src/theme/_smui-theme.scss +0 -0
- data/templates/tool_svelte/src/tool_name.js +0 -0
- data/templates/tool_vue/.env.standalone +0 -0
- data/templates/tool_vue/.gitignore +0 -0
- data/templates/tool_vue/.prettierrc.cjs +0 -0
- data/templates/tool_vue/eslint.config.mjs +0 -0
- data/templates/tool_vue/jsconfig.json +0 -0
- data/templates/tool_vue/package.json +3 -3
- data/templates/tool_vue/src/App.vue +0 -0
- data/templates/tool_vue/src/main.js +0 -0
- data/templates/tool_vue/src/router.js +0 -0
- data/templates/tool_vue/src/tools/tool_name/tool_name.vue +0 -0
- data/templates/tool_vue/vite.config.js +1 -1
- data/templates/widget/.prettierrc.cjs +0 -0
- data/templates/widget/LICENSE.md +0 -0
- data/templates/widget/Rakefile +0 -0
- data/templates/widget/package.json +2 -2
- data/templates/widget/src/Widget.vue +0 -0
- data/templates/widget/vite.config.js +0 -0
- metadata +36 -9
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 OpenC3, Inc.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is distributed in the hope that it will be useful,
|
|
7
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
8
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
9
|
+
# See LICENSE.md for more details.
|
|
10
|
+
#
|
|
11
|
+
# This file may also be used under the terms of a commercial license
|
|
12
|
+
# if purchased from OpenC3, Inc.
|
|
13
|
+
|
|
14
|
+
require 'open3'
|
|
15
|
+
require 'openc3/models/target_model'
|
|
16
|
+
require 'openc3/utilities/target_file'
|
|
17
|
+
|
|
18
|
+
module OpenC3
|
|
19
|
+
module PythonVenv
|
|
20
|
+
PLUGIN_VENVS_DIR = '/gems/plugin_venvs'
|
|
21
|
+
|
|
22
|
+
# Shared user site-packages directory used by plugins that predate the
|
|
23
|
+
# per-plugin UV venvs. Every caller that falls back off a plugin venv points
|
|
24
|
+
# PYTHONUSERBASE here, so keep it in one place rather than repeating the
|
|
25
|
+
# literal in script.rb, running_script.rb, microservice_operator.rb and
|
|
26
|
+
# microservice_model.rb.
|
|
27
|
+
DEFAULT_PYTHONUSERBASE = '/gems/python_packages'
|
|
28
|
+
|
|
29
|
+
# Packages a plugin venv must never supply itself. The scripts and
|
|
30
|
+
# microservices that use a plugin venv still run the base venv's Python
|
|
31
|
+
# binary, and CPython searches every PYTHONPATH entry ahead of the running
|
|
32
|
+
# venv's own site-packages. A plugin that declares openc3 as a dependency
|
|
33
|
+
# would therefore shadow the system library with its own copy, silently
|
|
34
|
+
# swapping the API client the script talks to COSMOS with. Reordering
|
|
35
|
+
# PYTHONPATH cannot fix this - the whole variable outranks the base venv -
|
|
36
|
+
# so the copy is removed at install time instead.
|
|
37
|
+
RESERVED_PACKAGES = ['openc3'].freeze
|
|
38
|
+
|
|
39
|
+
# Resolve a script's plugin venv and expose its packages to a child process.
|
|
40
|
+
# Returns the venv path when configured, or nil when the system environment
|
|
41
|
+
# should be used.
|
|
42
|
+
def self.configure_for_script(environment, name:, scope:, python_venv: nil)
|
|
43
|
+
venv_dir = resolve_script_venv(name: name, scope: scope, python_venv: python_venv)
|
|
44
|
+
return nil unless venv_dir
|
|
45
|
+
|
|
46
|
+
configure_environment(environment, venv_dir)
|
|
47
|
+
venv_dir
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def self.configure_environment(environment, venv_dir)
|
|
51
|
+
environment['VIRTUAL_ENV'] = venv_dir
|
|
52
|
+
environment['PATH'] = "#{venv_dir}/bin:#{ENV.fetch('PATH', '')}"
|
|
53
|
+
environment['PYTHONUSERBASE'] = venv_dir
|
|
54
|
+
|
|
55
|
+
site_packages = Dir.glob("#{venv_dir}/lib/python*/site-packages").first
|
|
56
|
+
# Prefer a PYTHONPATH the caller already seeded on `environment` over the
|
|
57
|
+
# ambient one. Script.process_suite sets it to ENV['PYTHONPATH'] || '.'
|
|
58
|
+
# before calling here, and reading ENV directly would drop that value.
|
|
59
|
+
existing_pythonpath = environment['PYTHONPATH'] || ENV.fetch('PYTHONPATH', '')
|
|
60
|
+
if site_packages
|
|
61
|
+
environment['PYTHONPATH'] = existing_pythonpath.empty? ? site_packages : "#{site_packages}:#{existing_pythonpath}"
|
|
62
|
+
else
|
|
63
|
+
environment['PYTHONPATH'] = existing_pythonpath.empty? ? nil : existing_pythonpath
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
environment
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Remove any RESERVED_PACKAGES a plugin installed into its own venv.
|
|
70
|
+
# Returns the names that were removed so callers can report them.
|
|
71
|
+
def self.purge_reserved_packages(venv_dir)
|
|
72
|
+
return [] if venv_dir.nil? || venv_dir.empty?
|
|
73
|
+
|
|
74
|
+
purged = []
|
|
75
|
+
RESERVED_PACKAGES.each do |package|
|
|
76
|
+
next unless package_installed?(venv_dir, package)
|
|
77
|
+
|
|
78
|
+
Logger.warn("Plugin venv #{venv_dir} declares '#{package}', which would shadow the " \
|
|
79
|
+
"system library. Removing it; the plugin will use the system #{package}.")
|
|
80
|
+
_output, status = Open3.capture2e('uv', 'pip', 'uninstall', '--python', venv_dir, package)
|
|
81
|
+
if status.success?
|
|
82
|
+
purged << package
|
|
83
|
+
else
|
|
84
|
+
Logger.error("Failed to remove '#{package}' from plugin venv #{venv_dir}")
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
purged
|
|
88
|
+
rescue => e
|
|
89
|
+
Logger.error("Could not purge reserved packages from #{venv_dir}: #{e.message}")
|
|
90
|
+
[]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def self.package_installed?(venv_dir, package)
|
|
94
|
+
_output, status = Open3.capture2e('uv', 'pip', 'show', '--python', venv_dir, package)
|
|
95
|
+
status.success?
|
|
96
|
+
end
|
|
97
|
+
private_class_method :package_installed?
|
|
98
|
+
|
|
99
|
+
def self.plugin_venv_path(scope:, plugin_name:)
|
|
100
|
+
sanitized_name = "#{scope}__#{plugin_name}".tr('^a-zA-Z0-9_-', '_')
|
|
101
|
+
candidate = File.join(PLUGIN_VENVS_DIR, sanitized_name, '.venv')
|
|
102
|
+
candidate if File.directory?(candidate)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def self.resolve_script_venv(name:, scope:, python_venv: nil)
|
|
106
|
+
target_name = name.split('/')[0].to_s.upcase
|
|
107
|
+
if target_name == TargetFile::TEMP_FOLDER && python_venv
|
|
108
|
+
# File.basename strips directory components; the tr() then whitelists the
|
|
109
|
+
# name down to the character set PluginModel.plugin_venv_name builds it
|
|
110
|
+
# from. That leaves no path separators and no glob metacharacters, so
|
|
111
|
+
# the value cannot escape PLUGIN_VENVS_DIR or widen the Dir.glob in
|
|
112
|
+
# configure_environment.
|
|
113
|
+
safe_name = File.basename(python_venv.to_s).tr('^a-zA-Z0-9_-', '_')
|
|
114
|
+
# The venv name is client-supplied, so it must also be confined to the
|
|
115
|
+
# caller's scope. Venv directories are named "<scope>__<plugin>" by
|
|
116
|
+
# PluginModel.plugin_venv_name; without this check a user in one scope
|
|
117
|
+
# could name another scope's venv and run against its packages.
|
|
118
|
+
return nil unless safe_name.start_with?("#{scope}__".tr('^a-zA-Z0-9_-', '_'))
|
|
119
|
+
|
|
120
|
+
candidate = File.join(PLUGIN_VENVS_DIR, safe_name, '.venv')
|
|
121
|
+
return candidate if File.directory?(candidate)
|
|
122
|
+
else
|
|
123
|
+
target_info = TargetModel.get(name: target_name, scope: scope)
|
|
124
|
+
if target_info && target_info['plugin']
|
|
125
|
+
return plugin_venv_path(scope: scope, plugin_name: target_info['plugin'])
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
nil
|
|
129
|
+
rescue => e
|
|
130
|
+
Logger.debug("Could not resolve plugin venv for script '#{name}': #{e.message}")
|
|
131
|
+
nil
|
|
132
|
+
end
|
|
133
|
+
private_class_method :resolve_script_venv
|
|
134
|
+
end
|
|
135
|
+
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# encoding: ascii-8bit
|
|
2
|
+
|
|
3
|
+
# Copyright 2026 OpenC3, Inc.
|
|
4
|
+
# All Rights Reserved.
|
|
5
|
+
#
|
|
6
|
+
# This program is distributed in the hope that it will be useful,
|
|
7
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
8
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
9
|
+
# See LICENSE.md for more details.
|
|
10
|
+
#
|
|
11
|
+
# This file may also be used under the terms of a commercial license
|
|
12
|
+
# if purchased from OpenC3, Inc.
|
|
13
|
+
|
|
14
|
+
require 'uri'
|
|
15
|
+
require 'openc3/utilities/logger'
|
|
16
|
+
|
|
17
|
+
module OpenC3
|
|
18
|
+
class RubygemsUrl
|
|
19
|
+
DEFAULT = 'https://rubygems.org'
|
|
20
|
+
|
|
21
|
+
# Validate that a resolved rubygems_url is an http(s) URL before it is used
|
|
22
|
+
# as a Gem source. The value can come from a user-writable setting or ENV, so
|
|
23
|
+
# a malformed or non-http value is rejected and replaced with the default
|
|
24
|
+
# rather than passed through to RubyGems.
|
|
25
|
+
#
|
|
26
|
+
# @param rubygems_url [String] the resolved rubygems source url to validate
|
|
27
|
+
# @return [String] the original url if valid, otherwise DEFAULT
|
|
28
|
+
def self.validate(rubygems_url)
|
|
29
|
+
uri = URI.parse(rubygems_url)
|
|
30
|
+
unless uri.is_a?(URI::HTTP) && !uri.host.to_s.empty?
|
|
31
|
+
raise URI::InvalidURIError, "not an http(s) URL"
|
|
32
|
+
end
|
|
33
|
+
rubygems_url
|
|
34
|
+
rescue URI::InvalidURIError => e
|
|
35
|
+
Logger.error("Invalid rubygems_url '#{rubygems_url}' (#{e.message}); falling back to #{DEFAULT}")
|
|
36
|
+
DEFAULT
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -28,6 +28,7 @@ require 'openc3/utilities/script'
|
|
|
28
28
|
require 'openc3/utilities/store'
|
|
29
29
|
require 'openc3/utilities/store_queued'
|
|
30
30
|
require 'openc3/utilities/bucket_require'
|
|
31
|
+
require 'openc3/utilities/python_venv'
|
|
31
32
|
require 'openc3/models/offline_access_model'
|
|
32
33
|
require 'openc3/models/environment_model'
|
|
33
34
|
require 'openc3/models/script_engine_model'
|
|
@@ -36,7 +37,7 @@ require 'fileutils'
|
|
|
36
37
|
|
|
37
38
|
if not defined? RAILS_ROOT
|
|
38
39
|
if ENV['RAILS_ROOT']
|
|
39
|
-
RAILS_ROOT = ENV
|
|
40
|
+
RAILS_ROOT = ENV.fetch('RAILS_ROOT')
|
|
40
41
|
elsif defined? Rails
|
|
41
42
|
RAILS_ROOT = Rails.root
|
|
42
43
|
else
|
|
@@ -436,7 +437,7 @@ class RunningScript
|
|
|
436
437
|
extension = File.extname(name).to_s.downcase
|
|
437
438
|
script_engine = nil
|
|
438
439
|
if extension == '.py'
|
|
439
|
-
process_name = ENV
|
|
440
|
+
process_name = ENV.fetch('OPENC3_PYTHON_BIN', '/openc3/python/.venv/bin/python')
|
|
440
441
|
runner_path = File.join(RAILS_ROOT, 'scripts', 'run_script.py')
|
|
441
442
|
elsif extension == '.rb'
|
|
442
443
|
process_name = 'ruby'
|
|
@@ -449,7 +450,7 @@ class RunningScript
|
|
|
449
450
|
if script_engine_model
|
|
450
451
|
script_engine = script_engine_model.filename
|
|
451
452
|
if File.extname(script_engine).to_s.downcase == '.py'
|
|
452
|
-
process_name = ENV
|
|
453
|
+
process_name = ENV.fetch('OPENC3_PYTHON_BIN', '/openc3/python/.venv/bin/python')
|
|
453
454
|
runner_path = File.join(RAILS_ROOT, 'scripts', 'run_script.py')
|
|
454
455
|
else
|
|
455
456
|
process_name = 'ruby'
|
|
@@ -521,17 +522,17 @@ class RunningScript
|
|
|
521
522
|
|
|
522
523
|
# Set proper secrets for running script
|
|
523
524
|
process.environment['SECRET_KEY_BASE'] = nil
|
|
524
|
-
process.environment['OPENC3_REDIS_USERNAME'] = ENV
|
|
525
|
-
process.environment['OPENC3_REDIS_PASSWORD'] = ENV
|
|
526
|
-
process.environment['OPENC3_BUCKET_USERNAME'] = ENV
|
|
527
|
-
process.environment['OPENC3_BUCKET_PASSWORD'] = ENV
|
|
525
|
+
process.environment['OPENC3_REDIS_USERNAME'] = ENV.fetch('OPENC3_SR_REDIS_USERNAME', nil)
|
|
526
|
+
process.environment['OPENC3_REDIS_PASSWORD'] = ENV.fetch('OPENC3_SR_REDIS_PASSWORD', nil)
|
|
527
|
+
process.environment['OPENC3_BUCKET_USERNAME'] = ENV.fetch('OPENC3_SR_BUCKET_USERNAME', nil)
|
|
528
|
+
process.environment['OPENC3_BUCKET_PASSWORD'] = ENV.fetch('OPENC3_SR_BUCKET_PASSWORD', nil)
|
|
528
529
|
process.environment['OPENC3_SR_REDIS_USERNAME'] = nil
|
|
529
530
|
process.environment['OPENC3_SR_REDIS_PASSWORD'] = nil
|
|
530
531
|
process.environment['OPENC3_SR_BUCKET_USERNAME'] = nil
|
|
531
532
|
process.environment['OPENC3_SR_BUCKET_PASSWORD'] = nil
|
|
532
|
-
process.environment['OPENC3_API_CLIENT'] = ENV
|
|
533
|
+
process.environment['OPENC3_API_CLIENT'] = ENV.fetch('OPENC3_API_CLIENT', nil)
|
|
533
534
|
if model and model.offline_access_token
|
|
534
|
-
auth = OpenC3::OpenC3KeycloakAuthentication.new(ENV
|
|
535
|
+
auth = OpenC3::OpenC3KeycloakAuthentication.new(ENV.fetch('OPENC3_KEYCLOAK_URL', nil))
|
|
535
536
|
valid_token = auth.get_token_from_refresh_token(model.offline_access_token)
|
|
536
537
|
if valid_token
|
|
537
538
|
process.environment['OPENC3_API_TOKEN'] = model.offline_access_token
|
|
@@ -541,58 +542,26 @@ class RunningScript
|
|
|
541
542
|
raise "offline_access token invalid for script"
|
|
542
543
|
end
|
|
543
544
|
else
|
|
544
|
-
process.environment['OPENC3_API_USER'] = ENV
|
|
545
|
+
process.environment['OPENC3_API_USER'] = ENV.fetch('OPENC3_API_USER', nil)
|
|
545
546
|
if ENV['OPENC3_SERVICE_PASSWORD']
|
|
546
|
-
process.environment['OPENC3_API_PASSWORD'] = ENV
|
|
547
|
+
process.environment['OPENC3_API_PASSWORD'] = ENV.fetch('OPENC3_SERVICE_PASSWORD')
|
|
547
548
|
else
|
|
548
549
|
raise "No authentication available for script"
|
|
549
550
|
end
|
|
550
551
|
end
|
|
551
|
-
process.environment['GEM_HOME'] = ENV
|
|
552
|
+
process.environment['GEM_HOME'] = ENV.fetch('GEM_HOME', nil)
|
|
552
553
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
begin
|
|
559
|
-
target_name = name.split('/')[0].to_s.upcase
|
|
560
|
-
if target_name == '__TEMP__' && python_venv
|
|
561
|
-
# File.basename prevents path traversal (strips directory components)
|
|
562
|
-
safe_name = File.basename(python_venv.to_s)
|
|
563
|
-
candidate = "/gems/plugin_venvs/#{safe_name}/.venv"
|
|
564
|
-
python_venv_dir = candidate if File.directory?(candidate)
|
|
565
|
-
else
|
|
566
|
-
target_info = OpenC3::TargetModel.get(name: target_name, scope: scope)
|
|
567
|
-
if target_info && target_info['plugin']
|
|
568
|
-
sanitized_name = "#{scope}__#{target_info['plugin']}".tr('^a-zA-Z0-9_-', '_')
|
|
569
|
-
candidate = "/gems/plugin_venvs/#{sanitized_name}/.venv"
|
|
570
|
-
python_venv_dir = candidate if File.directory?(candidate)
|
|
571
|
-
end
|
|
572
|
-
end
|
|
573
|
-
rescue => e
|
|
574
|
-
OpenC3::Logger.debug("Could not resolve plugin venv for script '#{name}': #{e.message}")
|
|
575
|
-
end
|
|
576
|
-
|
|
577
|
-
if python_venv_dir
|
|
578
|
-
process.environment['VIRTUAL_ENV'] = python_venv_dir
|
|
579
|
-
process.environment['PATH'] = "#{python_venv_dir}/bin:#{ENV.fetch('PATH', '')}"
|
|
580
|
-
process.environment['PYTHONUSERBASE'] = python_venv_dir
|
|
581
|
-
# Add plugin venv site-packages to PYTHONPATH so the base venv's Python
|
|
582
|
-
# binary can find plugin-specific packages. PYTHONPATH is always respected
|
|
583
|
-
# by CPython regardless of venv activation state.
|
|
584
|
-
site_packages = Dir.glob("#{python_venv_dir}/lib/python*/site-packages").first
|
|
585
|
-
existing_pythonpath = ENV.fetch('PYTHONPATH', '')
|
|
586
|
-
if site_packages
|
|
587
|
-
process.environment['PYTHONPATH'] = existing_pythonpath.empty? ? site_packages : "#{site_packages}:#{existing_pythonpath}"
|
|
588
|
-
else
|
|
589
|
-
process.environment['PYTHONPATH'] = existing_pythonpath.empty? ? nil : existing_pythonpath
|
|
590
|
-
end
|
|
591
|
-
else
|
|
592
|
-
system_venv = File.dirname(ENV['OPENC3_PYTHON_BIN'] || '/openc3/python/.venv/bin/python').chomp('/bin')
|
|
554
|
+
python_venv_dir = OpenC3::PythonVenv.configure_for_script(
|
|
555
|
+
process.environment, name: name, scope: scope, python_venv: python_venv
|
|
556
|
+
)
|
|
557
|
+
unless python_venv_dir
|
|
558
|
+
system_venv = File.dirname(ENV.fetch('OPENC3_PYTHON_BIN', '/openc3/python/.venv/bin/python')).chomp('/bin')
|
|
593
559
|
process.environment['VIRTUAL_ENV'] = system_venv
|
|
594
|
-
process.environment['PYTHONUSERBASE'] = ENV
|
|
595
|
-
|
|
560
|
+
process.environment['PYTHONUSERBASE'] = ENV.fetch('PYTHONUSERBASE', OpenC3::PythonVenv::DEFAULT_PYTHONUSERBASE)
|
|
561
|
+
# Deliberately nil when PYTHONPATH is unset rather than defaulting to
|
|
562
|
+
# something like '.', which would put the script's own working directory
|
|
563
|
+
# on the import path and let a local file shadow a real module.
|
|
564
|
+
process.environment['PYTHONPATH'] = ENV.fetch('PYTHONPATH', nil)
|
|
596
565
|
end
|
|
597
566
|
|
|
598
567
|
# Spawned process should not be controlled by same Bundler constraints as spawning process
|
|
@@ -1556,7 +1525,7 @@ class RunningScript
|
|
|
1556
1525
|
$stdout = OpenC3::Stdout.instance
|
|
1557
1526
|
$stderr = OpenC3::Stderr.instance
|
|
1558
1527
|
OpenC3::Logger.stdout = true
|
|
1559
|
-
OpenC3::Logger.level = OpenC3::Logger
|
|
1528
|
+
OpenC3::Logger.level = OpenC3::Logger.default_level
|
|
1560
1529
|
end
|
|
1561
1530
|
|
|
1562
1531
|
def output_thread
|
|
@@ -3,9 +3,9 @@ require 'aws-sdk-s3'
|
|
|
3
3
|
if ENV['OPENC3_CLOUD'] == 'local'
|
|
4
4
|
Aws.config.update(
|
|
5
5
|
s3: {
|
|
6
|
-
endpoint: ENV
|
|
7
|
-
access_key_id: ENV
|
|
8
|
-
secret_access_key: ENV
|
|
6
|
+
endpoint: ENV.fetch('OPENC3_BUCKET_URL', nil) || (ENV['OPENC3_DEVEL'] ? 'http://127.0.0.1:9000' : 'http://openc3-buckets:9000'),
|
|
7
|
+
access_key_id: ENV.fetch('OPENC3_BUCKET_USERNAME', nil),
|
|
8
|
+
secret_access_key: ENV.fetch('OPENC3_BUCKET_PASSWORD', nil),
|
|
9
9
|
force_path_style: true,
|
|
10
10
|
region: 'us-east-1',
|
|
11
11
|
# Disable automatic checksum calculation for S3-compatible backends (versitygw)
|
|
@@ -20,9 +20,9 @@ if ENV['OPENC3_CLOUD'] == 'local'
|
|
|
20
20
|
else # AWS
|
|
21
21
|
Aws.config.update(
|
|
22
22
|
s3: {
|
|
23
|
-
endpoint: "https://s3.#{ENV
|
|
23
|
+
endpoint: "https://s3.#{ENV.fetch('AWS_REGION', nil)}.amazonaws.com",
|
|
24
24
|
force_path_style: true,
|
|
25
|
-
region: ENV
|
|
25
|
+
region: ENV.fetch('AWS_REGION', nil)
|
|
26
26
|
}
|
|
27
27
|
)
|
|
28
28
|
end
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
require 'tempfile'
|
|
19
19
|
require 'openc3/utilities/target_file'
|
|
20
|
+
require 'openc3/utilities/python_venv'
|
|
20
21
|
require 'openc3/utilities/running_script'
|
|
21
22
|
require 'openc3/script/suite'
|
|
22
23
|
require 'openc3/script/suite_runner'
|
|
@@ -37,12 +38,6 @@ class Script < OpenC3::TargetFile
|
|
|
37
38
|
super(scope, nil, target: target) # No path matchers
|
|
38
39
|
end
|
|
39
40
|
|
|
40
|
-
# Split off the '*' that indicates a file is modified on the server
|
|
41
|
-
def self.strip_modified(name)
|
|
42
|
-
name.split('*')[0]
|
|
43
|
-
end
|
|
44
|
-
private_class_method :strip_modified
|
|
45
|
-
|
|
46
41
|
def self.lock(scope, name, username)
|
|
47
42
|
OpenC3::Store.hset("#{scope}__script-locks", strip_modified(name), username)
|
|
48
43
|
end
|
|
@@ -88,7 +83,7 @@ class Script < OpenC3::TargetFile
|
|
|
88
83
|
username: username, comment: comment)
|
|
89
84
|
end
|
|
90
85
|
|
|
91
|
-
def self.process_suite(name, contents, new_process: true, username: nil, scope:)
|
|
86
|
+
def self.process_suite(name, contents, new_process: true, username: nil, scope:, python_venv: nil)
|
|
92
87
|
python = false
|
|
93
88
|
python = true if File.extname(name) == '.py'
|
|
94
89
|
|
|
@@ -155,10 +150,19 @@ class Script < OpenC3::TargetFile
|
|
|
155
150
|
end
|
|
156
151
|
end
|
|
157
152
|
process.environment['GEM_HOME'] = ENV['GEM_HOME'] || '/gems'
|
|
158
|
-
process.environment['PYTHONUSERBASE'] = ENV['PYTHONUSERBASE'] ||
|
|
153
|
+
process.environment['PYTHONUSERBASE'] = ENV['PYTHONUSERBASE'] || OpenC3::PythonVenv::DEFAULT_PYTHONUSERBASE
|
|
159
154
|
# Preserve PYTHONPATH to ensure Python can find both UV venv and user packages
|
|
160
155
|
process.environment['PYTHONPATH'] = ENV['PYTHONPATH'] || '.'
|
|
161
156
|
|
|
157
|
+
# Suite analysis executes Python in a separate process before the script
|
|
158
|
+
# itself is started. Give that process the same plugin venv visibility as
|
|
159
|
+
# RunningScript so imports used while defining a suite can be resolved.
|
|
160
|
+
if python
|
|
161
|
+
OpenC3::PythonVenv.configure_for_script(
|
|
162
|
+
process.environment, name: name, scope: scope, python_venv: python_venv
|
|
163
|
+
)
|
|
164
|
+
end
|
|
165
|
+
|
|
162
166
|
# Spawned process should not be controlled by same Bundler constraints as spawning process
|
|
163
167
|
ENV.each do |key, _value|
|
|
164
168
|
if key =~ /^BUNDLE/
|
|
@@ -15,13 +15,58 @@ ENV['OPENC3_SECRET_BACKEND'] ||= 'redis'
|
|
|
15
15
|
|
|
16
16
|
module OpenC3
|
|
17
17
|
class Secrets
|
|
18
|
+
# Default base directory that FILE type secret paths must reside under.
|
|
19
|
+
# FILE type secrets are written by the operator (or mounted by Kubernetes)
|
|
20
|
+
# and then read back by the microservice, so the path is a destination we
|
|
21
|
+
# control, not an arbitrary file on the host.
|
|
22
|
+
DEFAULT_SECRET_FILE_DIR = '/tmp'
|
|
23
|
+
|
|
18
24
|
def initialize
|
|
19
25
|
@local_secrets = {}
|
|
20
26
|
end
|
|
21
27
|
|
|
28
|
+
# Base directory that FILE type secret paths must reside under
|
|
29
|
+
def self.secret_file_dir
|
|
30
|
+
dir = ENV.fetch('OPENC3_SECRET_FILE_DIR', nil)
|
|
31
|
+
dir = DEFAULT_SECRET_FILE_DIR if dir.nil? or dir.empty?
|
|
32
|
+
dir
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Validates a FILE type secret path. The path must expand to a location
|
|
36
|
+
# strictly inside Secrets.secret_file_dir. This prevents a plugin
|
|
37
|
+
# configuration such as 'SECRET FILE KEY /root/.ssh/id_rsa' or
|
|
38
|
+
# 'SECRET FILE KEY /tmp/../etc/shadow' from reading or overwriting arbitrary
|
|
39
|
+
# files as the OpenC3 process user.
|
|
40
|
+
#
|
|
41
|
+
# @param path [String] Path from a SECRET FILE definition
|
|
42
|
+
# @return [String] The validated absolute path
|
|
43
|
+
def self.validate_file_path(path)
|
|
44
|
+
raise ArgumentError, "Secret file path must be a String but is a #{path.class}" unless path.is_a?(String)
|
|
45
|
+
raise ArgumentError, "Secret file path must not be blank" if path.strip.empty?
|
|
46
|
+
raise ArgumentError, "Secret file path must not contain a null byte" if path.include?("\x00")
|
|
47
|
+
|
|
48
|
+
# expand_path collapses '..' and '.', expands '~', and makes a relative path
|
|
49
|
+
# absolute, so the comparison below can't be walked out of. This is
|
|
50
|
+
# deliberately a purely lexical check: it does not touch the filesystem, so
|
|
51
|
+
# a path validates identically at plugin install time (cmd-tlm-api) and at
|
|
52
|
+
# write time (openc3-operator), which are separate containers. Symlinks are
|
|
53
|
+
# rejected by the operator when it writes the secret.
|
|
54
|
+
base = File.expand_path(secret_file_dir)
|
|
55
|
+
absolute = File.expand_path(path)
|
|
56
|
+
unless absolute.start_with?(base + File::SEPARATOR)
|
|
57
|
+
raise ArgumentError, "Secret file path '#{path}' must be under '#{base}'"
|
|
58
|
+
end
|
|
59
|
+
absolute
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @return true if path is inside base, or is base itself
|
|
63
|
+
def self.path_contained?(base, path)
|
|
64
|
+
path == base or path.start_with?(base.end_with?(File::SEPARATOR) ? base : base + File::SEPARATOR)
|
|
65
|
+
end
|
|
66
|
+
|
|
22
67
|
def self.getClient
|
|
23
68
|
raise 'OPENC3_SECRET_BACKEND environment variable is required' unless ENV['OPENC3_SECRET_BACKEND']
|
|
24
|
-
secrets_class = ENV
|
|
69
|
+
secrets_class = ENV.fetch('OPENC3_SECRET_BACKEND').capitalize + 'Secrets'
|
|
25
70
|
klass = OpenC3.require_class('openc3/utilities/' + secrets_class.class_name_to_filename)
|
|
26
71
|
klass.new
|
|
27
72
|
end
|
|
@@ -50,9 +95,9 @@ module OpenC3
|
|
|
50
95
|
type, key, data, _secret_store = secret
|
|
51
96
|
case type
|
|
52
97
|
when 'ENV'
|
|
53
|
-
@local_secrets[key] = ENV
|
|
98
|
+
@local_secrets[key] = ENV.fetch(data, nil)
|
|
54
99
|
when 'FILE'
|
|
55
|
-
@local_secrets[key] = File.read(data)
|
|
100
|
+
@local_secrets[key] = File.read(Secrets.validate_file_path(data))
|
|
56
101
|
else
|
|
57
102
|
raise "Unknown secret type: #{type}"
|
|
58
103
|
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -116,8 +116,8 @@ module OpenC3
|
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
def initialize(pool_size = 10, db_shard: 0)
|
|
119
|
-
@redis_username = ENV
|
|
120
|
-
@redis_key = ENV
|
|
119
|
+
@redis_username = ENV.fetch('OPENC3_REDIS_USERNAME', nil)
|
|
120
|
+
@redis_key = ENV.fetch('OPENC3_REDIS_PASSWORD', nil)
|
|
121
121
|
hostname = ENV['OPENC3_REDIS_HOSTNAME'].to_s.gsub("SHARDNUM", db_shard.to_s)
|
|
122
122
|
@redis_url = "redis://#{hostname}:#{ENV.fetch('OPENC3_REDIS_PORT', 6379)}"
|
|
123
123
|
@redis_pool = StoreConnectionPool.new(size: pool_size) { build_redis() }
|
|
File without changes
|
|
@@ -21,6 +21,16 @@ module OpenC3
|
|
|
21
21
|
# Matches ScriptRunner.vue const TEMP_FOLDER
|
|
22
22
|
TEMP_FOLDER = '__TEMP__'
|
|
23
23
|
|
|
24
|
+
# self.all appends '*' to a name to mark it as modified on the server. The
|
|
25
|
+
# marker is display-only, so every path in and out of the bucket strips it.
|
|
26
|
+
#
|
|
27
|
+
# Strip only '*' at the end of a file name. '*' is a legal S3 object key character
|
|
28
|
+
# and is allowed by FileOpenSaveDialog's filename charset, so files named that
|
|
29
|
+
# way exist in the field and have to stay addressable.
|
|
30
|
+
def self.strip_modified(name)
|
|
31
|
+
name.sub(/\*$/, '')
|
|
32
|
+
end
|
|
33
|
+
|
|
24
34
|
def self.all(scope, path_matchers, target: nil)
|
|
25
35
|
target = target.upcase if target
|
|
26
36
|
|
|
@@ -89,7 +99,7 @@ module OpenC3
|
|
|
89
99
|
end
|
|
90
100
|
|
|
91
101
|
def self.body(scope, name)
|
|
92
|
-
name = name
|
|
102
|
+
name = strip_modified(name) # Remove '*' that indicates modified
|
|
93
103
|
# First try opening a potentially modified version by looking for the modified target
|
|
94
104
|
if ENV['OPENC3_LOCAL_MODE']
|
|
95
105
|
local_file = OpenC3::LocalMode.open_local_file(name, scope: scope)
|
|
@@ -122,6 +132,10 @@ module OpenC3
|
|
|
122
132
|
|
|
123
133
|
def self.create(scope, name, text, content_type: 'text/plain')
|
|
124
134
|
return false unless text
|
|
135
|
+
# A trailing '*' here is the display-only modified marker leaking in from a
|
|
136
|
+
# file listing, not a name any caller means to write. Remove it to avoid
|
|
137
|
+
# creating a file with a '*' in the name.
|
|
138
|
+
name = strip_modified(name)
|
|
125
139
|
if ENV['OPENC3_LOCAL_MODE']
|
|
126
140
|
OpenC3::LocalMode.put_target_file("#{scope}/targets_modified/#{name}", text, scope: scope)
|
|
127
141
|
end
|
|
@@ -146,6 +160,9 @@ module OpenC3
|
|
|
146
160
|
end
|
|
147
161
|
|
|
148
162
|
def self.destroy(scope, name)
|
|
163
|
+
# Match body/create so deleting a name taken straight from a listing
|
|
164
|
+
# removes the file the user actually picked
|
|
165
|
+
name = strip_modified(name)
|
|
149
166
|
if ENV['OPENC3_LOCAL_MODE']
|
|
150
167
|
OpenC3::LocalMode.delete_local("#{scope}/targets_modified/#{name}")
|
|
151
168
|
end
|
|
File without changes
|
|
File without changes
|
data/lib/openc3/utilities/zip.rb
CHANGED
|
File without changes
|
data/lib/openc3/utilities.rb
CHANGED
|
File without changes
|
data/lib/openc3/version.rb
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# encoding: ascii-8bit
|
|
2
2
|
|
|
3
|
-
OPENC3_VERSION = '7.
|
|
3
|
+
OPENC3_VERSION = '7.4.0'
|
|
4
4
|
module OpenC3
|
|
5
5
|
module Version
|
|
6
6
|
MAJOR = '7'
|
|
7
|
-
MINOR = '
|
|
7
|
+
MINOR = '4'
|
|
8
8
|
PATCH = '0'
|
|
9
9
|
OTHER = ''
|
|
10
|
-
BUILD = '
|
|
10
|
+
BUILD = 'ed0cb44ca3c661eaf2babb77664d0063c955c68c'
|
|
11
11
|
end
|
|
12
|
-
VERSION = '7.
|
|
13
|
-
GEM_VERSION = '7.
|
|
12
|
+
VERSION = '7.4.0'
|
|
13
|
+
GEM_VERSION = '7.4.0'
|
|
14
14
|
end
|
data/lib/openc3/win32/excel.rb
CHANGED
|
File without changes
|
data/lib/openc3/win32/win32.rb
CHANGED
|
File without changes
|
|
File without changes
|
data/lib/openc3.rb
CHANGED
|
@@ -30,9 +30,9 @@ $VERBOSE = saved_verbose
|
|
|
30
30
|
# Add OpenC3 bin folder to PATH
|
|
31
31
|
require 'openc3/core_ext/kernel'
|
|
32
32
|
if Kernel.is_windows?
|
|
33
|
-
ENV['PATH'] = File.join(File.dirname(__FILE__), '../bin') + ';' + ENV
|
|
33
|
+
ENV['PATH'] = File.join(File.dirname(__FILE__), '../bin') + ';' + ENV.fetch('PATH')
|
|
34
34
|
else
|
|
35
|
-
ENV['PATH'] = File.join(File.dirname(__FILE__), '../bin') + ':' + ENV
|
|
35
|
+
ENV['PATH'] = File.join(File.dirname(__FILE__), '../bin') + ':' + ENV.fetch('PATH')
|
|
36
36
|
end
|
|
37
37
|
require 'openc3/ext/platform' if RUBY_ENGINE == 'ruby' and !ENV['OPENC3_NO_EXT']
|
|
38
38
|
require 'openc3/version'
|
data/tasks/gemfile_stats.rake
CHANGED
|
File without changes
|
data/tasks/spec.rake
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
data/templates/plugin/.gitignore
CHANGED
|
File without changes
|
data/templates/plugin/LICENSE.md
CHANGED
|
File without changes
|
data/templates/plugin/README.md
CHANGED
|
File without changes
|
data/templates/plugin/Rakefile
CHANGED
|
File without changes
|
|
File without changes
|
data/templates/plugin/plugin.txt
CHANGED
|
File without changes
|