Prepare for the Path resolver change to GET (#9958)

- Prepares for the Cloud API change, together with a fallback for the old API to avoid problems during migration.
- This PR should be merged before the https://github.com/enso-org/cloud-v2/pull/1236 PR is _deployed_.
This commit is contained in:
Radosław Waśko 2024-05-15 15:00:32 +02:00 committed by GitHub
parent a53b2f0b18
commit a2481036e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 397 additions and 755 deletions

View File

@ -432,7 +432,7 @@ Enso_Asset_Type.from (that:Text) = case that of
"file" -> Enso_Asset_Type.File
"directory" -> Enso_Asset_Type.Directory
"secret" -> Enso_Asset_Type.Secret
"connector" -> Enso_Asset_Type.Data_Link
"datalink" -> Enso_Asset_Type.Data_Link
_ -> Error.throw (Illegal_Argument.Error "Invalid asset type: "+that.pretty+".")
## PRIVATE

View File

@ -11,6 +11,7 @@ import project.Enso_Cloud.Cloud_Caching_Settings
import project.Enso_Cloud.Enso_File.Enso_Asset_Type
import project.Enso_Cloud.Enso_File.Enso_File
import project.Enso_Cloud.Enso_User.Enso_User
import project.Enso_Cloud.Errors.Enso_Cloud_Error
import project.Enso_Cloud.Internal.Utils
import project.Error.Error
import project.Errors.Common.Not_Found
@ -18,6 +19,7 @@ import project.Errors.File_Error.File_Error
import project.Errors.Illegal_Argument.Illegal_Argument
import project.Errors.Unimplemented.Unimplemented
import project.Network.HTTP.HTTP_Method.HTTP_Method
import project.Network.URI.URI
import project.Runtime.Context
from project.Data.Boolean import Boolean, False, True
from project.Data.Text.Extensions import all
@ -82,12 +84,17 @@ type Existing_Enso_Asset
handle_not_found _ = if_not_found
error_handlers = Map.from_vector [["resource_missing", handle_not_found]]
uri = Utils.cloud_root_uri+"path/resolve"
payload = JS_Object.from_pairs [["path", path]]
# TODO remove workaround - this should be a Get endpoint, not Post
response = Context.Output.with_enabled <|
Utils.http_request_as_json HTTP_Method.Post uri payload error_handlers=error_handlers
uri = ((URI.from Utils.cloud_root_uri) / "path/resolve") . add_query_argument "path" path
r = Utils.http_request_as_json HTTP_Method.Get uri error_handlers=error_handlers
## Workaround to keep compatibility with old cloud API
TODO remove it after https://github.com/enso-org/cloud-v2/pull/1236 has been deployed
response = r.catch Enso_Cloud_Error error-> case error of
Enso_Cloud_Error.Unexpected_Service_Error status _ ->
if status.code != 404 then r else
old_uri = (URI.from Utils.cloud_root_uri) / "path/resolve"
old_payload = JS_Object.from_pairs [["path", path]]
Context.Output.with_enabled <| Utils.http_request_as_json HTTP_Method.Post old_uri old_payload error_handlers=error_handlers
_ -> r
Existing_Enso_Asset.from_json response
## PRIVATE

1075
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -177,8 +177,10 @@ type Mock_Credentials
type Temporary_Directory
Value ~get
timestamp_text -> Text = Date_Time.now.format "yyyy-MM-dd_HHmmss.fV" . replace "/" "."
make (name : Text) (with_initializer : (Enso_File -> Any) = (_->Nothing)) -> Temporary_Directory = Temporary_Directory.Value <|
directory_name = "test-run-"+name+"-"+(Date_Time.now.format "yyyy-MM-dd_HHmmss.fV" . replace "/" "|")
directory_name = "test-run-"+name+"-"+Temporary_Directory.timestamp_text
test_root = (Enso_File.root / directory_name).create_directory
with_initializer test_root . if_not_error test_root

View File

@ -33,9 +33,10 @@ add_specs suite_builder setup:Cloud_Tests_Setup =
Enso_Secret.list . should_be_a Vector
group_builder.specify "should allow to create, list and delete secrets" <| setup.with_prepared_environment <|
my_secret = Enso_Secret.create "my_test_secret" "my_secret_value"
name = "my_test_secret"+Temporary_Directory.timestamp_text
my_secret = Enso_Secret.create name "my_secret_value"
my_secret.should_succeed
my_secret.name . should_equal "my_test_secret"
my_secret.name . should_equal name
my_secret.id.is_empty . should_be_false
delete_on_fail my_secret <| Test.with_retries <|
@ -47,26 +48,28 @@ add_specs suite_builder setup:Cloud_Tests_Setup =
Enso_Secret.list . should_not_contain my_secret
group_builder.specify "should allow to get a secret by name or path" <| setup.with_prepared_environment <|
created_secret = Enso_Secret.create "my_test_secret-2" "my_secret_value"
name = "my-test-secret-2-"+Temporary_Directory.timestamp_text
created_secret = Enso_Secret.create name "my_secret_value"
created_secret.should_succeed
Panic.with_finalizer created_secret.delete <|
Test.with_retries <|
fetched_secret = Enso_Secret.get "my_test_secret-2"
fetched_secret = Enso_Secret.get name
fetched_secret . should_equal created_secret
path_secret = Enso_Secret.get "enso://"+Enso_User.current.organization_name+"/my_test_secret-2"
path_secret = Enso_Secret.get "enso://"+Enso_User.current.organization_name+"/"+name
path_secret . should_equal created_secret
group_builder.specify "does not allow both parent and path in Enso_Secret.get" <| setup.with_prepared_environment <|
Enso_Secret.get "enso://"+Enso_User.current.organization_name+"/SOME-SECRET" parent=Enso_File.root . should_fail_with Illegal_Argument
group_builder.specify "should fail to create a secret if it already exists" <| setup.with_prepared_environment <|
created_secret = Enso_Secret.create "my_test_secret-3" "my_secret_value"
name = "my_test_secret-3-"+Temporary_Directory.timestamp_text
created_secret = Enso_Secret.create name "my_secret_value"
created_secret.should_succeed
wait_until_secret_is_propagated created_secret
Panic.with_finalizer created_secret.delete <|
Test.with_retries <|
r1 = Enso_Secret.create "my_test_secret-3" "my_secret_value"
r1 = Enso_Secret.create name "my_secret_value"
## If the secret was created due to race condition - we clean it up
TODO: this should be addressed at Cloud level, disallowing to create a secret with the same name
@ -76,7 +79,7 @@ add_specs suite_builder setup:Cloud_Tests_Setup =
r1.catch.to_display_text . should_contain "already exists"
group_builder.specify "should allow to use secrets in HTTPS request headers" pending=setup.httpbin_pending <| setup.with_prepared_environment <|
secret1 = Enso_Secret.create "my_test_secret-6" "Yet another Mystery"
secret1 = Enso_Secret.create "my_test_secret-6"+Temporary_Directory.timestamp_text "Yet another Mystery"
secret1.should_succeed
Panic.with_finalizer secret1.delete <| Test.with_retries <|
@ -85,7 +88,7 @@ add_specs suite_builder setup:Cloud_Tests_Setup =
response.decode_as_json.at "headers" . at "X-My-Secret" . should_equal "Yet another Mystery"
group_builder.specify "should allow to derive values from secrets in Header.authorization_bearer" pending=setup.httpbin_pending <| setup.with_prepared_environment <|
secret_token = Enso_Secret.create "my_test_secret-7" "MySecretToken"
secret_token = Enso_Secret.create "my_test_secret-7"+Temporary_Directory.timestamp_text "MySecretToken"
secret_token.should_succeed
Panic.with_finalizer secret_token.delete <| Test.with_retries <|
@ -95,10 +98,10 @@ add_specs suite_builder setup:Cloud_Tests_Setup =
response_json.at "headers" . at "Authorization" . should_equal "Bearer MySecretToken"
group_builder.specify "should allow to derive values from secrets in Header.authorization_basic" pending=setup.httpbin_pending <| setup.with_prepared_environment <|
secret_username = Enso_Secret.create "my_test_secret-8" "MyUsername"
secret_username = Enso_Secret.create "my_test_secret-8"+Temporary_Directory.timestamp_text "MyUsername"
secret_username.should_succeed
Panic.with_finalizer secret_username.delete <|
secret_password = Enso_Secret.create "my_test_secret-9" "MyP@ssword"
secret_password = Enso_Secret.create "my_test_secret-9"+Temporary_Directory.timestamp_text "MyP@ssword"
secret_password.should_succeed
Panic.with_finalizer secret_password.delete <| Test.with_retries <|
https = setup.httpbin_secure_client
@ -109,7 +112,7 @@ add_specs suite_builder setup:Cloud_Tests_Setup =
response_json.at "headers" . at "Authorization" . should_equal expected
group_builder.specify "should allow to derive values from secrets" <| setup.with_prepared_environment <|
secret1 = Enso_Secret.create "my_test_secret-10" "Something"
secret1 = Enso_Secret.create "my_test_secret-10"+Temporary_Directory.timestamp_text "Something"
secret1.should_succeed
Panic.with_finalizer secret1.delete <| Test.with_retries <|
x = Derived_Secret_Value.from "X"
@ -135,7 +138,7 @@ add_specs suite_builder setup:Cloud_Tests_Setup =
b2.to_text . should_equal "base64(X__SECRET__)"
group_builder.specify "does not allow secrets in HTTP headers" pending=setup.httpbin_pending <| setup.with_prepared_environment <|
secret1 = Enso_Secret.create "my_test_secret-11" "Something"
secret1 = Enso_Secret.create "my_test_secret-11"+Temporary_Directory.timestamp_text "Something"
secret1.should_succeed
Panic.with_finalizer secret1.delete <| Test.with_retries <|
uri = setup.httpbin_uri / "get"
@ -144,7 +147,7 @@ add_specs suite_builder setup:Cloud_Tests_Setup =
r1.catch.to_display_text . should_contain "Secrets are not allowed in HTTP connections, use HTTPS instead."
group_builder.specify "API exposing secrets to external libraries should not be accessible from unauthorized code" <| setup.with_prepared_environment <|
secret1 = Enso_Secret.create "my_test_secret-12" "Something"
secret1 = Enso_Secret.create "my_test_secret-12"+Temporary_Directory.timestamp_text "Something"
secret1.should_succeed
Panic.with_finalizer secret1.delete <| Test.with_retries <|
java_repr = as_hideable_value secret1
@ -221,7 +224,7 @@ add_specs suite_builder setup:Cloud_Tests_Setup =
group_builder.specify "should be able to retry fetching a secret if the token is expired" pending=setup.httpbin_pending <| setup.with_prepared_environment <|
mock_setup = Cloud_Tests_Setup.prepare_mock_setup
mock_setup.with_prepared_environment <|
secret1 = Enso_Secret.create "my_test_secret-"+Random.uuid "Something123"
secret1 = Enso_Secret.create "my_test_secret-"+Temporary_Directory.timestamp_text "Something123"
secret1.should_succeed
Panic.with_finalizer secret1.delete <|
credentials = Mock_Credentials.default mock_setup.httpbin_uri . remotely_expired

View File

@ -5,6 +5,7 @@ from Standard.Table import all
from Standard.Test import all
import enso_dev.Base_Tests.Network.Enso_Cloud.Cloud_Tests_Setup.Cloud_Tests_Setup
import enso_dev.Base_Tests.Network.Enso_Cloud.Cloud_Tests_Setup.Temporary_Directory
import project.Util
@ -20,7 +21,7 @@ add_specs suite_builder =
group_builder.specify "writing Excel" <|
t = Table.new [["X", [1, 2, 3]], ["Y", ["a", "b", "c"]]]
f = Enso_File.root / "write-test-"+(Date_Time.now.format "yyyy-MM-dd_HHmmss.fV" . replace "/" "|")+".xlsx"
f = Enso_File.root / "write-test-"+Temporary_Directory.timestamp_text+".xlsx"
t.write f . should_equal f
Panic.with_finalizer f.delete_if_exists <|
workbook = f.read

View File

@ -1,6 +1,5 @@
package org.enso.shttp.cloud_mock;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.regex.Pattern;
@ -27,8 +26,19 @@ public class PathResolver implements CloudHandler {
@Override
public void handleCloudAPI(CloudExchange exchange) throws IOException {
JsonNode root = jsonMapper.readTree(exchange.decodeBodyAsText());
String path = root.get("path").asText();
String queryString = exchange.getHttpExchange().getRequestURI().getQuery();
if (queryString == null) {
exchange.sendResponse(400, "Missing `path` parameter in query string (empty).");
return;
}
String prefix = "path=";
if (!queryString.startsWith(prefix)) {
exchange.sendResponse(400, "Missing `path` parameter in query string: `" + queryString + "`");
return;
}
String path = queryString.substring(prefix.length());
var matcher = pathPattern.matcher(path);
if (!matcher.matches()) {
exchange.sendResponse(400, "Invalid path: " + path);