Skip to content

Conversation

@vsilent
Copy link
Collaborator

@vsilent vsilent commented Feb 2, 2026

No description provided.

vsilent added 30 commits December 25, 2025 21:21
- Add MCP protocol types with JSON-RPC 2.0 support
- Implement WebSocket handler with heartbeat mechanism
- Create tool registry with pluggable handler architecture
- Add session management for conversation context
- Register /mcp WebSocket endpoint with OAuth auth
- Add Casbin rules for group_user and group_admin access
- Include comprehensive unit tests for protocol layer

Components:
- src/mcp/protocol.rs: JSON-RPC 2.0 + MCP types
- src/mcp/websocket.rs: Actix WebSocket actor
- src/mcp/registry.rs: Tool handler infrastructure
- src/mcp/session.rs: Session state management
- migrations/20251227140000: Casbin authorization rules

Dependencies:
- actix 0.13.5 (WebSocket actor framework)
- actix-web-actors 4.3.1 (Actix-web WS integration)
- async-trait 0.1.77 (Tool handler trait)

Supports:
- initialize, tools/list, tools/call methods
- OAuth bearer token authentication
- Casbin role-based authorization
- Structured logging with tracing
- Graceful connection handling
@gitguardian
Copy link

gitguardian bot commented Feb 2, 2026

⚠️ GitGuardian has uncovered 6 secrets following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secrets in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
24149610 Triggered Bearer Token bd423f5 src/connectors/admin_service/jwt.rs View secret
25120004 Triggered Hashicorp Vault Token 1f483ee config-to-validate.yaml View secret
9658888 Triggered Generic Password 0a5afab config-to-validate.yaml View secret
26598182 Triggered influxdb_token 16b5a2a src/project_app/tests.rs View secret
25120005 Triggered Generic High Entropy Secret 1f483ee config-to-validate.yaml View secret
25120006 Triggered Generic High Entropy Secret 0a5afab test_agent_report.sh View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secrets safely. Learn here the best practices.
  3. Revoke and rotate these secrets.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

@vsilent vsilent requested a review from Copilot February 2, 2026 15:38
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request implements a comprehensive user service refactoring that adds external service connectors, enhances configuration management, and improves deployment workflows.

Changes:

  • Introduced a new connectors module with User Service, Docker Hub, Install Service, and Admin Service integrations
  • Simplified database delete operations by removing unnecessary transactions
  • Added configuration versioning and deployment settings with environment variable support
  • Enhanced CI/CD workflows with multi-platform builds and improved caching

Reviewed changes

Copilot reviewed 134 out of 344 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/db/project.rs Simplified delete operation by removing transaction overhead
src/db/cloud.rs Simplified delete operation by removing transaction overhead
src/db/agreement.rs Simplified delete operation by removing transaction overhead
src/db/deployment.rs Added new fetch methods for deployment lookup by hash and project
src/db/command.rs Enhanced command fetching with new methods for ID and command_id lookup
src/connectors/* New connector infrastructure for external service integrations
src/configuration.rs Added comprehensive configuration with defaults and environment overrides
Cargo.toml Updated dependencies for connectors and async operations
.github/workflows/* Enhanced CI/CD with multi-platform builds and improved caching
Files not reviewed (88)
  • .sqlx/query-0bb6c35cba6f3c5573cf45c42b93709286b2a50446caa2a609aaf77af12b30bb.json: Language not supported
  • .sqlx/query-0dab58aa1022e2c1f4320f232195f54d89279057657c92305f606522fa142cf7.json: Language not supported
  • .sqlx/query-0f9023a3cea267596e9f99b3887012242345a8b4e4f9d838dc6d44cc34a89433.json: Language not supported
  • .sqlx/query-0faf1a2932ba1b37fc9f982bc86c323869489c6dc7e17479b647f0aa799df910.json: Language not supported
  • .sqlx/query-172dbb0c3947fa99e8522510096cd8dbfd785bb982a0622d3c05afb2ab3e260f.json: Language not supported
  • .sqlx/query-17f59e9f273d48aaf85b09c227f298f6d6f6f231554d80ed621076157af7f80a.json: Language not supported
  • .sqlx/query-1cabd2f674da323da9e0da724d3bcfe5f968b31500e8c8cf97fe16814bc04164.json: Language not supported
  • .sqlx/query-1f1b8182d59d8253662da0ea73b69b6857e5f3c8f4292ba9c4491e062591575b.json: Language not supported
  • .sqlx/query-1f299262f01a2c9d2ee94079a12766573c91b2775a086c65bc9a5fdc91300bb0.json: Language not supported
  • .sqlx/query-24876462291b90324dfe3682e9f36247a328db780a48da47c9402e1d3ebd80c9.json: Language not supported
  • .sqlx/query-2872b56bbc5bed96b1a303bf9cf44610fb79a1b9330730c65953f0c1b88c2a53.json: Language not supported
  • .sqlx/query-2c7065ccf4a0a527087754db39a2077a054026cb2bc0c010aba218506e76110f.json: Language not supported
  • .sqlx/query-309c79e9f4b28e19488e71ca49974e0c9173f355d69459333acf181ff2a82a1c.json: Language not supported
  • .sqlx/query-327394e1777395afda4a1f6c1ca07431de81f886f6a8d6e0fbcd7b6633d30b98.json: Language not supported
  • .sqlx/query-32d118e607db4364979c52831e0c30a215779928a041ef51e93383e93288aac2.json: Language not supported
  • .sqlx/query-36f6c8ba5c553e6c13d0041482910bc38e48635c4df0c73c211d345a26cccf4e.json: Language not supported
  • .sqlx/query-39d0d9c946cbd9cdacff0d59a39a6c331091879a27faeabbebf1602c797b22ea.json: Language not supported
  • .sqlx/query-3b6ec5ef58cb3b234d8c8d45641339d172624d59fff7494f1929c8fe37f564a4.json: Language not supported
  • .sqlx/query-3dd9013b8856be2d991a656c3cdd77692bd1a336be4d06ff6e0ac6831164617e.json: Language not supported
  • .sqlx/query-3efacedb58ab13dad5eeaa4454a4d82beb1dedc0f62405d008f18045df981277.json: Language not supported
  • .sqlx/query-41edb5195e8e68b8c80c8412f5bb93cf4838bd1e7e668dafd0fffbd13c90d5aa.json: Language not supported
  • .sqlx/query-438ee38e669be96e562d09d3bc5806b4c78b7aa2a9609c4eccb941c7dff7b107.json: Language not supported
  • .sqlx/query-467365894a7f9a0888584e8879cac289299f4d03539b9c746324cd183e265553.json: Language not supported
  • .sqlx/query-4acfe0086a593b08177791bb3b47cb75a999041a3eb6a8f8177bebfa3c30d56f.json: Language not supported
  • .sqlx/query-4bdcd8d475ffd8aab728ec2b9d0d8c578770e2d52bf531de6e69561a4adbb21c.json: Language not supported
  • .sqlx/query-4e375cca55b0f106578474e5736094044e237999123952be7c78b46c937b8778.json: Language not supported
  • .sqlx/query-4e7b82d256f7298564f46af6a45b89853785c32a5f83cb0b25609329c760428a.json: Language not supported
  • .sqlx/query-4ed4ce17b28e36898d9afabb96b7043ceee664f67752c41bf06df6e51ed69362.json: Language not supported
  • .sqlx/query-4f54a93856a693345a9f63552dabf3192c3108a2776bb56f36787af3fa884554.json: Language not supported
  • .sqlx/query-4fbb395f2080f29291ea091d2c4135b962e41b4e5b49d20e9d5fee3da051aeba.json: Language not supported
  • .sqlx/query-53a76c5d7dbb79cb51cace5ffacc2cf689a650fb90bccfb80689ef3c5b73a2b0.json: Language not supported
  • .sqlx/query-546d2bb7ff653c0ae1f6dcc5e68b12a670230de592557d27159acd2fc09400c6.json: Language not supported
  • .sqlx/query-55e886a505d00b70674a19fd3228915ab4494cbd7058fdec868ab93c0fcfb4d8.json: Language not supported
  • .sqlx/query-5bf9f8aacbe676339d0811d305abace6cc4a4d068392f7b58f2d165042ab509e.json: Language not supported
  • .sqlx/query-5d36c126c67a5b70ac168bc46fcff3ee63ae5548ce78f244099f9d61ca694312.json: Language not supported
  • .sqlx/query-5fea60d7574cfd238a7cbae4d93423869bd7b79dd5b246d80f0b6f39ce4659dc.json: Language not supported
  • .sqlx/query-6cdfab7ffca4a98abcd7fb2325289ccf3035f08340bf80a345ff74570cd62043.json: Language not supported
  • .sqlx/query-6e44fd63bcb2075e9515a7ce3d0be7a3759a98b5f1c637eb632aa440a1ffadb6.json: Language not supported
  • .sqlx/query-722e059fca26aa3be81451ef5e266cc32d0e3ebc0611bd69013b6c3aa240b674.json: Language not supported
  • .sqlx/query-7466afe658bdac4d522b96b33e769c130a1c5d065df70ce221490356c7eb806a.json: Language not supported
  • .sqlx/query-7a6b4eb7eefd541ecb0529783ac01c36b2e69902623f289bd3cc6bf73d2b0ce8.json: Language not supported
  • .sqlx/query-7b6c7e798237d0c08b7c1126d7044df13c46ef2eb373398a535090edf738cb5a.json: Language not supported
  • .sqlx/query-7c087b528df89eb0bf41a4e46bcc48ab4946535a96baf0f49996d79387a3791c.json: Language not supported
  • .sqlx/query-8038cec278228a04f83f4d67f8e2fd0382be589bf5d6dcde690b63f281160159.json: Language not supported
  • .sqlx/query-8218dc7f0a2d15d19391bdcde1dfe27d2ee90aa4598b17d90e5db82244ad6ff1.json: Language not supported
  • .sqlx/query-82eb411b1d8f6f3bed3db367ea147fbcd0626347744c7f8de6dce25d6e9a1fe7.json: Language not supported
  • .sqlx/query-836ec7786ee20369b6b49aa89587480579468a5cb4ecdf7b315920b5e0bd894c.json: Language not supported
  • .sqlx/query-83769682ee9bf8c76f1058a71b11d7d009683eef134e7be5b4ac285333822f58.json: Language not supported
  • .sqlx/query-83cd9d573480c8a83e9e58f375653b4d76ec4c4dea338877ef5ba72fa49c28ad.json: Language not supported
  • .sqlx/query-8aafae4565e572dc36aef3bb3d7b82a392e59683b9dfa1c457974e8fa8b7d00f.json: Language not supported
  • .sqlx/query-8b3df91d5aec320fa8ffa47fc4d7fe61abe05cd5f4635d135d92dd605d065f56.json: Language not supported
  • .sqlx/query-8bc673f6b9422bdc0e1f7b3aae61b851fb9d7b74a3ec519c9149f4948880d1be.json: Language not supported
  • .sqlx/query-8cfb2d3a45ff6c5d1d51a98f6a37ba89da5a49c211c8627c314b8a32c92a62e1.json: Language not supported
  • .sqlx/query-8db13c16e29b4aecd87646859296790f3e5971d7a2bff2d32f2d92590ec3393d.json: Language not supported
  • .sqlx/query-8ec4c1e77a941efe4c1c36e26c5e1dfcb0e7769f0333d2acf7d6e0fb97ca12dc.json: Language not supported
  • .sqlx/query-91966b9578edeb2303bbba93cfc756595265b21dd6f7a06a2f7a846d162b340c.json: Language not supported
  • .sqlx/query-954605527a3ca7b9d6cbf1fbc03dc00c95626c94f0f02cbc69336836f95ec45e.json: Language not supported
  • .sqlx/query-970e2fc198c379a19849c4621adeca951c761f6b9abd6c70158000e0c03ca7c7.json: Language not supported
  • .sqlx/query-9d821bd27d5202d2c3d49a2f148ff7f21bafde8c7c1306cc7efc976a9eae0071.json: Language not supported
  • .sqlx/query-9dc75c72351c3f0a7f2f13d1a638ff21ea671df07397a4f84fff3c2cb9bdec91.json: Language not supported
  • .sqlx/query-9e4f216c828c7d53547c33da062153f90eefabe5a252f86d5e8d1964785025c0.json: Language not supported
  • .sqlx/query-a24f6ae41366cfc2480a7d7832b1f823cc91662394ec8025b7ef486b85374411.json: Language not supported
  • .sqlx/query-aa21279e6479dd588317bbb4c522094f0cf8736710de08963fff1178f2b62974.json: Language not supported
  • .sqlx/query-ab22f5f84d90a3c2717cea339f6444c6c2656615fb29b4c04031a090cf103bdd.json: Language not supported
  • .sqlx/query-b8296183bd28695d3a7574e57db445dc1f4b2d659a3805f92f6f5f83b562266b.json: Language not supported
  • .sqlx/query-b92417574329b82cae2347027db12f4794c1fc48b67d64c34c88fd9caf4508f5.json: Language not supported
  • .sqlx/query-bc798b1837501109ff69f44c01d39c1cc03348eb4b4fe698ad06283ba7072b7f.json: Language not supported
  • .sqlx/query-c28d645182680aaeaf265abcb687ea36f2a01b6b778fd61921e0046ad3f2efb2.json: Language not supported
  • .sqlx/query-c59246b73cf3c5a0fd961d2709477ce724f60cdb03492eef912a9fe89aee2ac4.json: Language not supported
  • .sqlx/query-c9a83f9d610a79bef78e533dde75f527ab75ef319ef0584851feb5b893a9fa46.json: Language not supported
  • .sqlx/query-cd6ddae34b29c15924e0ec26ea55c23d56315ad817bea716d6a71c8b2bb18087.json: Language not supported
  • .sqlx/query-cf85345c0c38d7ba1c347a9cf027a55dccaaeb0fe55d5eabb7319a90cbdfe951.json: Language not supported
  • .sqlx/query-d6ef8d90061834e8352f036e7fd7853451c03b83261fa43e564e8ad98a41c943.json: Language not supported
  • .sqlx/query-d81dbcf77d096403614b80165d66388884b133c79da6ed1a5809a3ca64f48f97.json: Language not supported
  • .sqlx/query-db15f82b91377978db22c48cf2fb4d54ef603448c0c44272aec8f2ff04920b83.json: Language not supported
  • .sqlx/query-dd36c2beb4867d36db9dc0fe47e6310aea0a7dd4c8fc5f7c2cff4dac327cf3f7.json: Language not supported
  • .sqlx/query-e5956a76c15941c58fc9acb3886c9d8ed8688d70ac5fcceaf41e1671f75dbaa8.json: Language not supported
  • .sqlx/query-e5a60eb49da1cd42fc6c1bac36f038846f0cb4440e4b377d495ffe0f0bfc11b6.json: Language not supported
  • .sqlx/query-f0af06a2002ce933966cf6cfe8289ea77781df5a251a6731b42f8ddefb8a4c8b.json: Language not supported
  • .sqlx/query-f130c22d14ee2a99b9220ac1a45226ba97993ede9988a4c57d58bd066500a119.json: Language not supported
  • .sqlx/query-f8611a862ed1d3b982e8aa5ccab21e00c42a3fad8082cf15c2af88cd8388f41b.json: Language not supported
  • .sqlx/query-f93b65a30034b0558781a3173986706ad8a6255bba2812d4e32da205773c6de9.json: Language not supported
  • .sqlx/query-fa51ae7af271fc17c848694fbf1b37d46c5a2f4202e1b8dce1f66a65069beb0b.json: Language not supported
  • .sqlx/query-fb07f53c015c852c4ef9e0ce52541f06835f8687122987d87fad751981b0c2b1.json: Language not supported
  • .sqlx/query-fb7ce69e70b345d2cf0ca017523c1b90b67b053add3d4cffb8d579bfc8f08345.json: Language not supported
  • .sqlx/query-fde61fd37b0e4c325e9dd4817a5ccc4ed8a4ffd2175fce842dd5d33545ba63f2.json: Language not supported
  • .sqlx/query-ffb567ac44b9a0525bd41392c3a865d0612bc0d3f620d5cba76a6b44a8812417.json: Language not supported
  • .sqlx/query-ffd49d0e0354d8d4010863204b1a1f5406b31542b6b0219d7daa1705bf7b2f37.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -0,0 +1,16 @@
/// Helper function to determine if a plan tier can access a required plan
/// Basic idea: enterprise >= professional >= basic
pub(crate) fn is_plan_upgrade(user_plan: &str, required_plan: &str) -> bool {
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function name is_plan_upgrade is misleading. Based on the implementation (line 15: user_level > required_level), this function checks if the user's plan is higher tier than the required plan, not if it's an upgrade. Consider renaming to is_plan_higher_tier or has_plan_access to accurately reflect that it checks whether the user's plan meets or exceeds the requirement.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Comment on lines 264 to 266
if let Ok(enabled) = std::env::var("STACKER_CASBIN_RELOAD_ENABLED") {
config.casbin_reload_enabled = matches!(enabled.as_str(), "1" | "true" | "TRUE");
}
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The boolean parsing logic for environment variables is duplicated across multiple settings. Consider extracting this into a helper function like parse_bool_env(value: &str) -> bool that handles common boolean representations consistently.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback


database:
host: 172.17.0.2
host: stackerdb
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The database host has been changed from an IP address to a hostname. Ensure that DNS resolution or Docker networking is properly configured for the stackerdb hostname to be resolvable in the local development environment.

Suggested change
host: stackerdb
host: 127.0.0.1

Copilot uses AI. Check for mistakes.
});

self.client
.post(&path)

Check failure

Code scanning / CodeQL

Cleartext transmission of sensitive information High

This 'post' operation transmits data which may contain unencrypted sensitive data from
user_id
.
This 'post' operation transmits data which may contain unencrypted sensitive data from
user_id
.

Copilot Autofix

AI 2 days ago

In general terms, the right fix is to ensure that this Vault client never uses an unencrypted transport when sending sensitive data. In practice for this snippet, that means validating self.address at the point where we construct the request URL and rejecting any non-HTTPS scheme, so that we never perform .post() to an insecure HTTP endpoint. We do not need to change the structure of the payload or the use of user_id in the path; the critical improvement is to guarantee TLS in transit.

The single best way to fix this without changing existing functionality is:

  1. In store_ssh_key, instead of calling .post(&path) with a path string that might be missing a scheme or might use http://, parse path as a reqwest::Url (or as url::Url if preferred) and inspect its scheme.
  2. If the scheme is not exactly "https", return an error explaining that a secure Vault URL is required.
  3. Call .post(url) with the validated Url object instead of the raw string.

This preserves all existing behavior for valid HTTPS Vault addresses while preventing cleartext transmission of the SSH keypair. To implement this we can use reqwest::Url (re-export of url::Url) which is part of the same crate already in use (reqwest), so no new external dependencies are needed. All changes occur inside src/helpers/vault.rs, in the body of store_ssh_key, around lines 219–235 where path is computed and used.

Suggested changeset 1
src/helpers/vault.rs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/helpers/vault.rs b/src/helpers/vault.rs
--- a/src/helpers/vault.rs
+++ b/src/helpers/vault.rs
@@ -217,7 +217,18 @@
         private_key: &str,
     ) -> Result<String, String> {
         let path = self.ssh_key_path(user_id, server_id);
+        let url = reqwest::Url::parse(&path).map_err(|e| {
+            let msg = format!("Invalid Vault URL '{}': {}", path, e);
+            tracing::error!("{}", msg);
+            msg
+        })?;
 
+        if url.scheme() != "https" {
+            let msg = format!("Insecure Vault URL scheme '{}', HTTPS is required", url.scheme());
+            tracing::error!("{}", msg);
+            return Err(msg);
+        }
+
         let payload = json!({
             "data": {
                 "public_key": public_key,
@@ -229,7 +239,7 @@
         });
 
         self.client
-            .post(&path)
+            .post(url)
             .header("X-Vault-Token", &self.token)
             .json(&payload)
             .send()
EOF
@@ -217,7 +217,18 @@
private_key: &str,
) -> Result<String, String> {
let path = self.ssh_key_path(user_id, server_id);
let url = reqwest::Url::parse(&path).map_err(|e| {
let msg = format!("Invalid Vault URL '{}': {}", path, e);
tracing::error!("{}", msg);
msg
})?;

if url.scheme() != "https" {
let msg = format!("Insecure Vault URL scheme '{}', HTTPS is required", url.scheme());
tracing::error!("{}", msg);
return Err(msg);
}

let payload = json!({
"data": {
"public_key": public_key,
@@ -229,7 +239,7 @@
});

self.client
.post(&path)
.post(url)
.header("X-Vault-Token", &self.token)
.json(&payload)
.send()
Copilot is powered by AI and may make mistakes. Always verify output.

let response = self
.client
.get(&path)

Check failure

Code scanning / CodeQL

Cleartext transmission of sensitive information High

This 'get' operation transmits data which may contain unencrypted sensitive data from
user_id
.
This 'get' operation transmits data which may contain unencrypted sensitive data from
user_id
.

let response = self
.client
.get(&path)

Check failure

Code scanning / CodeQL

Cleartext transmission of sensitive information High

This 'get' operation transmits data which may contain unencrypted sensitive data from
user_id
.
This 'get' operation transmits data which may contain unencrypted sensitive data from
user_id
.
vsilent and others added 12 commits February 2, 2026 18:35
- Extract container states from recent health command results
- Build ContainerSnapshot array from HealthCommandReport data
- Fixes empty containers array that prevented UI from showing app status
- Make dedicated query for health commands to always get results
- Filter only completed health commands for container state extraction
- Fixes containers array being empty due to exclude_results optimization
- Use HashMap to keep only most recent health check per app
- Prevents duplicate container entries when multiple health checks exist
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI commented Feb 4, 2026

@vsilent I've opened a new pull request, #98, to work on those changes. Once the pull request is ready, I'll request review from you.

vsilent and others added 2 commits February 4, 2026 11:27
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI commented Feb 4, 2026

@vsilent I've opened a new pull request, #99, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 6 commits February 4, 2026 09:33
Co-authored-by: vsilent <42473+vsilent@users.noreply.github.com>
Co-authored-by: vsilent <42473+vsilent@users.noreply.github.com>
…arsing logic

Co-authored-by: vsilent <42473+vsilent@users.noreply.github.com>
Co-authored-by: vsilent <42473+vsilent@users.noreply.github.com>
Rename is_plan_upgrade to is_plan_higher_tier
Extract parse_bool_env helper to deduplicate boolean parsing logic
@vsilent vsilent merged commit 034fc50 into main Feb 4, 2026
2 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants