omnata-plugin-devkit 0.13.1a179__tar.gz → 0.13.2__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.
Files changed (89) hide show
  1. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/PKG-INFO +1 -1
  2. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/pyproject.toml +1 -1
  3. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/CONFIGURE_APIS.sql.jinja +2 -1
  4. omnata_plugin_devkit-0.13.2/src/omnata_plugin_devkit/jinja_templates/CREATE_GENERIC_SECRET_OBJECT.sql.jinja +50 -0
  5. omnata_plugin_devkit-0.13.2/src/omnata_plugin_devkit/jinja_templates/CREATE_GENERIC_SECRET_OBJECT_FROM_EXISTING.sql.jinja +82 -0
  6. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/RETRIEVE_SECRETS_UDF.sql.jinja +1 -4
  7. omnata_plugin_devkit-0.13.2/src/omnata_plugin_devkit/jinja_templates/SET_CONNECTION_OBJECTS.sql.jinja +357 -0
  8. omnata_plugin_devkit-0.13.1a179/src/omnata_plugin_devkit/jinja_templates/CREATE_GENERIC_SECRET_OBJECT.sql.jinja +0 -35
  9. omnata_plugin_devkit-0.13.1a179/src/omnata_plugin_devkit/jinja_templates/CREATE_GENERIC_SECRET_OBJECT_FROM_EXISTING.sql.jinja +0 -55
  10. omnata_plugin_devkit-0.13.1a179/src/omnata_plugin_devkit/jinja_templates/SET_CONNECTION_OBJECTS.sql.jinja +0 -357
  11. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/LICENSE +0 -0
  12. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/README.md +0 -0
  13. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/__init__.py +0 -0
  14. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/airbyte_wrapper.py +0 -0
  15. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/cli/__init__.py +0 -0
  16. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/development.ipynb +0 -0
  17. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/development_session.py +0 -0
  18. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/initialiser.py +0 -0
  19. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/API_LIMITS.sql.jinja +0 -0
  20. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/ASSIGN_OUTBOUND_TARGET_TYPE.sql.jinja +0 -0
  21. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/CHECK_CONNECTION_PROGRESS.sql.jinja +0 -0
  22. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/CONFIGURATION_FORM.sql.jinja +0 -0
  23. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/CONNECTION_FORM.sql.jinja +0 -0
  24. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/CONNECTION_TEST.sql.jinja +0 -0
  25. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/CONSTRUCT_FORM_OPTION.sql.jinja +0 -0
  26. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/CREATE_BILLING_EVENTS.sql.jinja +0 -0
  27. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/CREATE_NETWORK_RULE_OBJECT.sql.jinja +0 -0
  28. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/CREATE_NETWORK_RULE_OBJECT_FROM_EXISTING.sql.jinja +0 -0
  29. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/CREATE_OAUTH_SECRET_OBJECT.sql.jinja +0 -0
  30. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/DROP_NETWORK_RULES.sql.jinja +0 -0
  31. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/DROP_SECRETS.sql.jinja +0 -0
  32. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/FETCH_CONNECTIONS.sql.jinja +0 -0
  33. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/FETCH_SYNCS.sql.jinja +0 -0
  34. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/FETCH_SYNC_BRANCHES.sql.jinja +0 -0
  35. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/GET_MISSING_APP_PRIVILEGES.sql.jinja +0 -0
  36. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/INBOUND_LIST_STREAMS.sql.jinja +0 -0
  37. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/LIST_APP_SPECIFICATIONS.sql.jinja +0 -0
  38. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/LIST_STAGES.sql.jinja +0 -0
  39. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/NETWORK_ADDRESSES.sql.jinja +0 -0
  40. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/NGROK_POST_TUNNEL_FIELDS.sql.jinja +0 -0
  41. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/OUTBOUND_RECORD_VALIDATOR.sql.jinja +0 -0
  42. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/PENDING_API_CONFIGURATION.sql.jinja +0 -0
  43. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/POST_INSTALL_ACTIONS.sql.jinja +0 -0
  44. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/RENAME_CONNECTION_METHODS.sql.jinja +0 -0
  45. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/RETRIEVE_NETWORK_RULE_OBJECT.sql.jinja +0 -0
  46. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/RETRIEVE_SECRETS.sql.jinja +0 -0
  47. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/SET_EAI_ENABLED.sql.jinja +0 -0
  48. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/SET_EAI_SPECIFICATION.sql.jinja +0 -0
  49. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/SET_SI_SPECIFICATION.sql.jinja +0 -0
  50. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/SYNC.sql.jinja +0 -0
  51. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/TEST_CALLBACK.sql.jinja +0 -0
  52. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/TEST_OAUTH_TOKEN_EXISTS.sql.jinja +0 -0
  53. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/TUNNEL_TEST.sql.jinja +0 -0
  54. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/UPDATE_API_CONFIGURATION.sql.jinja +0 -0
  55. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/UPDATE_GENERIC_SECRET_OBJECT.sql.jinja +0 -0
  56. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/UPDATE_GENERIC_SECRET_OBJECT_OLD.sql.jinja +0 -0
  57. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/UPDATE_NETWORK_RULE_OBJECT.sql.jinja +0 -0
  58. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/jinja_templates/manifest.yml.jinja +0 -0
  59. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/native_app_packaging.py +0 -0
  60. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/plugin_registration.py +0 -0
  61. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/plugin_template/icon.svg +0 -0
  62. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/plugin_template/plugin.py +0 -0
  63. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/plugin_template/plugin_development.ipynb +0 -0
  64. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/plugin_template/requirements.txt +0 -0
  65. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/plugin_uploader.py +0 -0
  66. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/__init__.py +0 -0
  67. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/__init__.py +0 -0
  68. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/api/__init__.py +0 -0
  69. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/api/config.py +0 -0
  70. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/api/constants.py +0 -0
  71. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/api/exceptions.py +0 -0
  72. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/api/secure_path.py +0 -0
  73. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/api/secure_utils.py +0 -0
  74. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/api/utils/__init__.py +0 -0
  75. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/api/utils/types.py +0 -0
  76. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/app/__init__.py +0 -0
  77. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/app/snow_connector.py +0 -0
  78. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/plugins/__init__.py +0 -0
  79. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/__init__.py +0 -0
  80. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/models.py +0 -0
  81. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/package/__init__.py +0 -0
  82. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/package_utils.py +0 -0
  83. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/snowpark_shared.py +0 -0
  84. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/venv.py +0 -0
  85. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/plugins/snowpark/zipper.py +0 -0
  86. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/snowcli/cli/templates/environment.yml.jinja +0 -0
  87. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/streamlit/plugin_configuration.py +0 -0
  88. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/test_step_definitions.py +0 -0
  89. {omnata_plugin_devkit-0.13.1a179 → omnata_plugin_devkit-0.13.2}/src/omnata_plugin_devkit/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omnata-plugin-devkit
3
- Version: 0.13.1a179
3
+ Version: 0.13.2
4
4
  Summary:
5
5
  License-File: LICENSE
6
6
  Author: James Weakley
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "omnata-plugin-devkit"
3
- version = "0.13.1a179"
3
+ version = "0.13.2"
4
4
  description = ""
5
5
  authors = ["James Weakley <james.weakley@omnata.com>"]
6
6
  readme = "README.md"
@@ -323,7 +323,8 @@ try{
323
323
  OBJECT,
324
324
  VARCHAR,
325
325
  VARCHAR,
326
- VARCHAR)`
326
+ VARCHAR)`,
327
+ `SET_CONNECTION_OBJECTS(OBJECT)`
327
328
  ];
328
329
  procsToAlter.forEach(function(procToAlter) {
329
330
  var sqlText = `alter procedure ${procToAlter}
@@ -0,0 +1,50 @@
1
+ create or replace procedure PLUGIN.CREATE_GENERIC_SECRET_OBJECT(SECRET_NAME VARCHAR, SECRET_CONTENTS VARCHAR)
2
+ returns object
3
+ language python
4
+ RUNTIME_VERSION = '3.10'
5
+ PACKAGES = ({{packages}})
6
+ HANDLER = 'run'
7
+ COMMENT = $$
8
+ Creates a generic secret object. SECRET_STRING is written via a dollar-quoted
9
+ literal rather than a bind parameter: bind binding for SECRET_STRING = ? was
10
+ observed to interpret backslash escapes inside the value, turning a JSON `\n`
11
+ two-byte escape into a raw LF byte and corrupting the stored JSON. Dollar
12
+ quoting is byte-faithful.
13
+ $$
14
+ execute as owner
15
+ as
16
+ $$
17
+ from logging import getLogger
18
+ logger = getLogger(__name__)
19
+
20
+ # Avoid putting two literal dollar signs in this proc body (the body itself
21
+ # is dollar-quoted, so a stray pair of dollar signs would close it early).
22
+ _TWO_DOLLARS = "$" + "$"
23
+
24
+
25
+ def run(session, secret_name, secret_contents):
26
+ try:
27
+ if secret_contents is None:
28
+ secret_contents = ""
29
+ if _TWO_DOLLARS in secret_contents:
30
+ raise ValueError(
31
+ "secret_contents contains '" + _TWO_DOLLARS + "', which is "
32
+ "currently not supported due to Snowflake delimiter requirements."
33
+ )
34
+ sql = (
35
+ "CREATE OR REPLACE SECRET IDENTIFIER(?) TYPE = GENERIC_STRING "
36
+ "SECRET_STRING = " + _TWO_DOLLARS + secret_contents + _TWO_DOLLARS
37
+ )
38
+ session.sql(sql, params=[secret_name]).collect()
39
+ session.sql(
40
+ "grant usage on secret IDENTIFIER(?) to application role OMNATA_MANAGEMENT",
41
+ params=[secret_name],
42
+ ).collect()
43
+ return {"success": True, "data": None}
44
+ except Exception as e:
45
+ return {"success": False, "error": f"CREATE_GENERIC_SECRET_OBJECT: {str(e)}"}
46
+ $$
47
+ ;
48
+
49
+ grant usage on procedure PLUGIN.CREATE_GENERIC_SECRET_OBJECT(VARCHAR, VARCHAR)
50
+ to application role OMNATA_MANAGEMENT;
@@ -0,0 +1,82 @@
1
+ create or replace procedure PLUGIN.CREATE_GENERIC_SECRET_OBJECT_FROM_EXISTING(
2
+ SECRET_NAME VARCHAR,
3
+ SECRET_TO_CLONE VARCHAR,
4
+ KEYS_TO_INCLUDE ARRAY,
5
+ NEW_CONTENTS_TO_MERGE VARCHAR DEFAULT NULL
6
+ )
7
+ returns object
8
+ language python
9
+ RUNTIME_VERSION = '3.10'
10
+ PACKAGES = ({{packages}})
11
+ HANDLER = 'run'
12
+ COMMENT = $$
13
+ Creates a generic secret object using an existing secret as the seed.
14
+ - KEYS_TO_INCLUDE (optional): if provided, restrict the cloned content to
15
+ these keys before any merging.
16
+ - NEW_CONTENTS_TO_MERGE (optional): JSON object string whose entries are
17
+ merged on top of the cloned content (overwriting matching keys). Use
18
+ this to add or update fields in one shot without a second proc call.
19
+ The write itself is delegated to CREATE_GENERIC_SECRET_OBJECT, which uses a
20
+ dollar-quoted SECRET_STRING literal to avoid bind-parameter escape
21
+ interpretation that corrupts newlines in PEM values.
22
+ $$
23
+ execute as owner
24
+ as
25
+ $$
26
+ import json
27
+ from logging import getLogger
28
+ logger = getLogger(__name__)
29
+
30
+
31
+ def _call_proc(session, sql, params):
32
+ rows = session.sql(sql, params=params).collect()
33
+ if not rows:
34
+ raise RuntimeError(f"delegate proc returned no rows: {sql}")
35
+ val = rows[0][0]
36
+ if isinstance(val, str):
37
+ try:
38
+ val = json.loads(val)
39
+ except json.JSONDecodeError:
40
+ pass
41
+ if isinstance(val, dict) and val.get('success') is False:
42
+ raise RuntimeError(val.get('error') or f"delegate proc failed: {sql}")
43
+ return val.get('data') if isinstance(val, dict) else val
44
+
45
+
46
+ def run(session, secret_name, secret_to_clone, keys_to_include, new_contents_to_merge):
47
+ try:
48
+ existing = _call_proc(
49
+ session,
50
+ "call PLUGIN.RETRIEVE_SECRETS(NULL, ?)",
51
+ [secret_to_clone],
52
+ ) or {}
53
+ if not isinstance(existing, dict):
54
+ existing = {}
55
+ if keys_to_include is not None:
56
+ existing = {k: existing[k] for k in keys_to_include if k in existing}
57
+ if new_contents_to_merge is not None:
58
+ try:
59
+ new_dict = json.loads(new_contents_to_merge)
60
+ except (TypeError, json.JSONDecodeError) as parse_err:
61
+ raise ValueError(
62
+ f"NEW_CONTENTS_TO_MERGE must be a JSON object string: {parse_err}"
63
+ ) from parse_err
64
+ if not isinstance(new_dict, dict):
65
+ raise ValueError("NEW_CONTENTS_TO_MERGE must decode to a JSON object")
66
+ existing = {**existing, **new_dict}
67
+ _call_proc(
68
+ session,
69
+ "call PLUGIN.CREATE_GENERIC_SECRET_OBJECT(?, ?)",
70
+ [secret_name, json.dumps(existing)],
71
+ )
72
+ return {"success": True, "data": None}
73
+ except Exception as e:
74
+ return {
75
+ "success": False,
76
+ "error": f"CREATE_GENERIC_SECRET_OBJECT_FROM_EXISTING: {str(e)}",
77
+ }
78
+ $$
79
+ ;
80
+
81
+ grant usage on procedure PLUGIN.CREATE_GENERIC_SECRET_OBJECT_FROM_EXISTING(VARCHAR, VARCHAR, ARRAY, VARCHAR)
82
+ to application role OMNATA_MANAGEMENT;
@@ -35,7 +35,4 @@ def run(oauth_secret_name,other_secrets_name):
35
35
  raise ValueError(f"Error parsing secrets content: {str(exception)}") from exception
36
36
  return connection_secrets
37
37
  $$
38
- ;
39
-
40
- grant usage on function PLUGIN.RETRIEVE_SECRETS_UDF(VARCHAR,VARCHAR)
41
- to application role OMNATA_MANAGEMENT;
38
+ ;
@@ -0,0 +1,357 @@
1
+ create or replace procedure PLUGIN.SET_CONNECTION_OBJECTS(PARAMETERS OBJECT)
2
+ returns object
3
+ language python
4
+ RUNTIME_VERSION = '3.10'
5
+ PACKAGES = ({{packages}})
6
+ IMPORTS = ('/app.zip')
7
+ HANDLER = 'run'
8
+ COMMENT = $$
9
+ Creates or replaces every Snowflake object required to provision a connection: network
10
+ rules, OAuth security integration, OAuth secret, secret authorization configuration,
11
+ other_secrets generic secret, External Access Integration, EAI application specification,
12
+ and Security Integration application specification. OAuth-related objects are only created
13
+ when oauth_security_integration_name is provided.
14
+
15
+ Expected keys on PARAMETERS:
16
+ external_access_integration_name (required; account-level, no schema)
17
+ network_rule_name (required; unqualified — DATA schema is prepended)
18
+ network_addresses (required, array of strings)
19
+ network_rule_name_privatelink (optional; unqualified — DATA schema is prepended)
20
+ network_rule_addresses_privatelink (required if privatelink rule set)
21
+ oauth_security_integration_name (optional; account-level, no schema — enables the oauth branch)
22
+ oauth_parameters (required if oauth SI set; object with
23
+ oauth_grant, oauth_token_endpoint,
24
+ oauth_authorization_endpoint,
25
+ oauth_allowed_scopes, oauth_client_id,
26
+ oauth_client_secret)
27
+ oauth_secret_name (optional; unqualified — DATA schema is prepended; requires oauth SI)
28
+ oauth_secret_configuration_name (optional; application-scope, no schema; requires oauth_secret_name)
29
+ other_secrets_name (required; unqualified — DATA schema is prepended)
30
+ connection_secrets (optional object; merged into the generic secret
31
+ contents, overwriting any matching keys from
32
+ merge_with_secret_name)
33
+ merge_with_secret_name (optional; unqualified name of an existing generic
34
+ secret in DATA whose contents are read via
35
+ RETRIEVE_SECRETS_UDF and used as the baseline for
36
+ the new other_secrets generic secret.)
37
+ external_access_integration_spec_name (required; application-scope, no schema)
38
+ security_integration_spec_name (optional; application-scope, no schema; requires oauth SI)
39
+ connection_slug (required; human-readable connection identifier
40
+ included in spec labels/descriptions so the
41
+ consumer knows which connection they are
42
+ approving)
43
+ $$
44
+ execute as owner
45
+ as
46
+ $$
47
+ import json
48
+ import _snowflake
49
+ from logging import getLogger
50
+ from typing import Any, Dict, List, Literal, Optional
51
+ from pydantic import BaseModel, ConfigDict, Field, model_validator
52
+ from omnata_plugin_runtime.logging import log_exception
53
+ logger = getLogger(__name__)
54
+
55
+ _IDENT_PATTERN = r'^[A-Za-z_][A-Za-z0-9_$.]*$'
56
+ _BARE_IDENT_PATTERN = r'^[A-Za-z_][A-Za-z0-9_$]*$'
57
+ _BARE_IDENT_HINT = "must be an unqualified identifier (no schema prefix; DATA. is prepended automatically)"
58
+
59
+
60
+ class OAuthParameters(BaseModel):
61
+ model_config = ConfigDict(extra='allow')
62
+ oauth_grant: Literal['authorization_code', 'client_credentials'] = 'authorization_code'
63
+ oauth_token_endpoint: Optional[str] = None
64
+ oauth_authorization_endpoint: Optional[str] = None
65
+ oauth_allowed_scopes: Optional[List[str]] = None
66
+ oauth_client_id: Optional[str] = None
67
+ oauth_client_secret: Optional[str] = None
68
+
69
+
70
+ class SetConnectionParameters(BaseModel):
71
+ model_config = ConfigDict(extra='ignore')
72
+
73
+ external_access_integration_name: str = Field(pattern=_IDENT_PATTERN, max_length=255)
74
+ network_rule_name: str = Field(pattern=_BARE_IDENT_PATTERN, max_length=255, description=_BARE_IDENT_HINT)
75
+ network_addresses: List[str]
76
+ network_rule_name_privatelink: Optional[str] = Field(default=None, pattern=_BARE_IDENT_PATTERN, max_length=255, description=_BARE_IDENT_HINT)
77
+ network_rule_addresses_privatelink: Optional[List[str]] = None
78
+ oauth_security_integration_name: Optional[str] = Field(default=None, pattern=_IDENT_PATTERN, max_length=255)
79
+ oauth_parameters: Optional[OAuthParameters] = None
80
+ oauth_secret_name: Optional[str] = Field(default=None, pattern=_BARE_IDENT_PATTERN, max_length=255, description=_BARE_IDENT_HINT)
81
+ oauth_secret_configuration_name: Optional[str] = Field(default=None, pattern=_IDENT_PATTERN, max_length=255)
82
+ other_secrets_name: str = Field(pattern=_BARE_IDENT_PATTERN, max_length=255, description=_BARE_IDENT_HINT)
83
+ connection_secrets: Optional[Dict[str, Any]] = None
84
+ merge_with_secret_name: Optional[str] = Field(default=None, pattern=_BARE_IDENT_PATTERN, max_length=255, description=_BARE_IDENT_HINT)
85
+ external_access_integration_spec_name: str = Field(pattern=_IDENT_PATTERN, max_length=255)
86
+ security_integration_spec_name: Optional[str] = Field(default=None, pattern=_IDENT_PATTERN, max_length=255)
87
+ connection_slug: str = Field(min_length=1, max_length=255)
88
+
89
+ @model_validator(mode='after')
90
+ def _check_combinations(self):
91
+ if self.network_rule_name_privatelink and self.network_rule_addresses_privatelink is None:
92
+ raise ValueError("network_rule_addresses_privatelink is required when network_rule_name_privatelink is provided")
93
+ if self.oauth_security_integration_name and self.oauth_parameters is None:
94
+ raise ValueError("oauth_parameters (object) is required when oauth_security_integration_name is provided")
95
+ if self.oauth_secret_name and not self.oauth_security_integration_name:
96
+ raise ValueError("oauth_security_integration_name is required when oauth_secret_name is provided")
97
+ if self.oauth_secret_configuration_name and not self.oauth_secret_name:
98
+ raise ValueError("oauth_secret_name is required when oauth_secret_configuration_name is provided")
99
+ if self.security_integration_spec_name and not self.oauth_security_integration_name:
100
+ raise ValueError("oauth_security_integration_name is required when security_integration_spec_name is provided")
101
+ return self
102
+
103
+
104
+ def _esc_sql(s):
105
+ return str(s).replace("'", "''")
106
+
107
+
108
+ def _call_proc(session, sql, params):
109
+ """Run `CALL PLUGIN.X(...)` and unwrap the {success, data|error} envelope.
110
+ Raises RuntimeError when success is false; returns `data` on success."""
111
+ rows = session.sql(sql, params=params).collect()
112
+ if not rows:
113
+ raise RuntimeError(f"delegate proc returned no rows: {sql}")
114
+ val = rows[0][0]
115
+ if isinstance(val, str):
116
+ try:
117
+ val = json.loads(val)
118
+ except json.JSONDecodeError:
119
+ pass
120
+ if isinstance(val, dict) and val.get('success') is False:
121
+ raise RuntimeError(val.get('error') or f"delegate proc failed: {sql}")
122
+ return val.get('data') if isinstance(val, dict) else val
123
+
124
+
125
+ def run(session, parameters):
126
+ try:
127
+ params = SetConnectionParameters.model_validate(parameters or {})
128
+
129
+ eai_name = params.external_access_integration_name
130
+ network_rule_name = params.network_rule_name
131
+ network_rule_fqn = f"DATA.{network_rule_name}"
132
+ network_addresses = params.network_addresses
133
+ eai_spec_name = params.external_access_integration_spec_name
134
+ connection_slug = params.connection_slug
135
+
136
+ privatelink_rule_name = params.network_rule_name_privatelink
137
+ privatelink_rule_fqn = f"DATA.{privatelink_rule_name}" if privatelink_rule_name else None
138
+ privatelink_addresses = params.network_rule_addresses_privatelink
139
+
140
+ oauth_si_name = params.oauth_security_integration_name
141
+ oauth_parameters = params.oauth_parameters
142
+ oauth_secret_name = params.oauth_secret_name
143
+ oauth_secret_fqn = f"DATA.{oauth_secret_name}" if oauth_secret_name else None
144
+ oauth_secret_config_name = params.oauth_secret_configuration_name
145
+ si_spec_name = params.security_integration_spec_name
146
+
147
+ other_secrets_name = params.other_secrets_name
148
+ other_secrets_fqn = f"DATA.{other_secrets_name}"
149
+ merge_with_secret_name = params.merge_with_secret_name
150
+ connection_secrets = params.connection_secrets
151
+
152
+ logger.info(f"SET_CONNECTION_OBJECTS: provisioning connection '{connection_slug}' (EAI {eai_name})")
153
+
154
+ # (1) Direct network rule — delegate to CREATE_NETWORK_RULE_OBJECT.
155
+ _call_proc(
156
+ session,
157
+ "call PLUGIN.CREATE_NETWORK_RULE_OBJECT(?, PARSE_JSON(?), ?)",
158
+ [network_rule_fqn, json.dumps(network_addresses), 'HOST_PORT'],
159
+ )
160
+
161
+ # (2) Privatelink network rule — optional.
162
+ if privatelink_rule_fqn:
163
+ _call_proc(
164
+ session,
165
+ "call PLUGIN.CREATE_NETWORK_RULE_OBJECT(?, PARSE_JSON(?), ?)",
166
+ [privatelink_rule_fqn, json.dumps(privatelink_addresses), 'PRIVATE_HOST_PORT'],
167
+ )
168
+
169
+ # (3) OAuth security integration — inline DDL (no existing proc).
170
+ if oauth_si_name:
171
+ op = oauth_parameters
172
+ oauth_grant = op.oauth_grant
173
+ oauth_token_ep = op.oauth_token_endpoint or ''
174
+ oauth_auth_ep = op.oauth_authorization_endpoint or ''
175
+ oauth_scopes = op.oauth_allowed_scopes or []
176
+ oauth_client_id = op.oauth_client_id
177
+ oauth_client_secret = op.oauth_client_secret
178
+
179
+ clauses = [
180
+ "TYPE = API_AUTHENTICATION",
181
+ "AUTH_TYPE = OAUTH2",
182
+ "OAUTH_CLIENT_AUTH_METHOD = CLIENT_SECRET_POST",
183
+ f"OAUTH_GRANT = {oauth_grant.upper()}",
184
+ ]
185
+ if oauth_grant == 'authorization_code' and oauth_auth_ep:
186
+ clauses.append(f"OAUTH_AUTHORIZATION_ENDPOINT = '{_esc_sql(oauth_auth_ep)}'")
187
+ if oauth_token_ep:
188
+ clauses.append(f"OAUTH_TOKEN_ENDPOINT = '{_esc_sql(oauth_token_ep)}'")
189
+ if oauth_scopes:
190
+ scope_parts = [f"'{_esc_sql(s)}'" for s in oauth_scopes]
191
+ clauses.append(f"OAUTH_ALLOWED_SCOPES = ({', '.join(scope_parts)})")
192
+ if oauth_client_id is not None:
193
+ clauses.append(f"OAUTH_CLIENT_ID = '{_esc_sql(oauth_client_id)}'")
194
+ if oauth_client_secret is not None:
195
+ clauses.append(f"OAUTH_CLIENT_SECRET = '{_esc_sql(oauth_client_secret)}'")
196
+ clauses.append("ENABLED = TRUE")
197
+
198
+ si_sql = "CREATE OR REPLACE SECURITY INTEGRATION IDENTIFIER(?)\n " + "\n ".join(clauses)
199
+ logger.info(f"Executing SQL: {si_sql}")
200
+ session.sql(si_sql, params=[oauth_si_name]).collect()
201
+ # USAGE on the security integration is required for any APPLICATION_ROLES listed in an
202
+ # ALTER APPLICATION SET CONFIGURATION DEFINITION SECRET_AUTHORIZATION (the referenced
203
+ # OAuth secret's API_AUTHENTICATION points to this integration).
204
+ session.sql(
205
+ "grant usage on integration IDENTIFIER(?) to application role OMNATA_MANAGEMENT",
206
+ params=[oauth_si_name],
207
+ ).collect()
208
+
209
+ # (4) OAuth secret — delegate to CREATE_OAUTH_SECRET_OBJECT.
210
+ if oauth_secret_fqn:
211
+ _call_proc(
212
+ session,
213
+ "call PLUGIN.CREATE_OAUTH_SECRET_OBJECT(?, ?)",
214
+ [oauth_secret_fqn, oauth_si_name],
215
+ )
216
+ # CREATE_OAUTH_SECRET_OBJECT grants USAGE only. MODIFY is required on the secret for
217
+ # any APPLICATION_ROLES listed in an ALTER APPLICATION SET CONFIGURATION DEFINITION
218
+ # SECRET_AUTHORIZATION, otherwise the configuration fails with
219
+ # "role ... is missing 'MODIFY' privilege on Secret".
220
+ session.sql(
221
+ "grant modify, usage on secret IDENTIFIER(?) to application role OMNATA_MANAGEMENT",
222
+ params=[oauth_secret_fqn],
223
+ ).collect()
224
+
225
+ # (5) Secret authorization configuration.
226
+ # https://docs.snowflake.com/en/developer-guide/native-apps/app-configuration-secret-authorization#step-5-create-the-secret-authorization-configuration
227
+ if oauth_secret_config_name:
228
+ # The secret name alternates its trailing __A / __B suffix on each edit; include that
229
+ # letter in the label so the edit-flow configuration is distinct from the prior one
230
+ # (configuration definition labels must be unique).
231
+ secret_alt = oauth_secret_name[-1]
232
+ cfg_label = f"Authorize OAuth connection: {connection_slug} ({secret_alt})"
233
+ cfg_description = (
234
+ f"Complete the OAuth flow so this application can access the external service "
235
+ f"for connection '{connection_slug}'"
236
+ )
237
+ cfg_sql = (
238
+ f"ALTER APPLICATION SET CONFIGURATION DEFINITION {oauth_secret_config_name}\n"
239
+ f" TYPE = SECRET_AUTHORIZATION\n"
240
+ f" SECRET = {oauth_secret_fqn}\n"
241
+ f" LABEL = '{_esc_sql(cfg_label)}'\n"
242
+ f" DESCRIPTION = '{_esc_sql(cfg_description)}'\n"
243
+ f" APPLICATION_ROLES = (OMNATA_MANAGEMENT)"
244
+ )
245
+ logger.info(f"Executing SQL: {cfg_sql}")
246
+ session.sql(cfg_sql).collect()
247
+
248
+ # (6) Other secrets — read the seed directly via _snowflake.get_generic_secret_string
249
+ # rather than going through RETRIEVE_SECRETS / CREATE_GENERIC_SECRET_OBJECT_FROM_EXISTING.
250
+ # The cross-proc VARCHAR bind path was observed to mangle backslash escapes in JSON
251
+ # payloads; reading the secret in-process avoids any extra hop. The secret must be
252
+ # bound to this proc by CONFIGURE_APIS — the alias is the unqualified name.
253
+ seed_secrets = {}
254
+ if merge_with_secret_name:
255
+ raw = _snowflake.get_generic_secret_string(merge_with_secret_name)
256
+ if raw and len(raw) > 2:
257
+ decoded = json.loads(raw)
258
+ if isinstance(decoded, dict):
259
+ seed_secrets = decoded
260
+ if connection_secrets:
261
+ seed_secrets.update(connection_secrets)
262
+ _call_proc(
263
+ session,
264
+ "call PLUGIN.CREATE_GENERIC_SECRET_OBJECT(?, ?)",
265
+ [other_secrets_fqn, json.dumps(seed_secrets)],
266
+ )
267
+
268
+ # (7) External Access Integration.
269
+ eai_rules = [network_rule_fqn]
270
+ if privatelink_rule_fqn:
271
+ eai_rules.append(privatelink_rule_fqn)
272
+ eai_secrets = [other_secrets_fqn]
273
+ if oauth_secret_fqn:
274
+ eai_secrets.append(oauth_secret_fqn)
275
+
276
+ eai_rules_sql = ', '.join(eai_rules)
277
+ eai_secrets_clause = ''
278
+ if eai_secrets:
279
+ eai_secrets_clause = f"\n ALLOWED_AUTHENTICATION_SECRETS = ({', '.join(eai_secrets)})"
280
+ eai_sql = (
281
+ f"CREATE OR REPLACE EXTERNAL ACCESS INTEGRATION IDENTIFIER(?)\n"
282
+ f" ALLOWED_NETWORK_RULES = ({eai_rules_sql})"
283
+ f"{eai_secrets_clause}\n"
284
+ f" ENABLED = FALSE"
285
+ )
286
+ logger.info(f"Executing SQL: {eai_sql}")
287
+ session.sql(eai_sql, params=[eai_name]).collect()
288
+ # Grant USAGE so the sync engine (via OMNATA_MANAGEMENT) can see/use the EAI.
289
+ session.sql(
290
+ "grant usage on integration IDENTIFIER(?) to application role OMNATA_MANAGEMENT",
291
+ params=[eai_name],
292
+ ).collect()
293
+
294
+ # (8) EAI application specification — delegate to SET_EAI_SPECIFICATION.
295
+ # Unlike for security integrations/configurations, this specification does not need to alternate when editing as it's not bound to any objects
296
+ eai_spec_props = {
297
+ "LABEL": f"External access for connection: {connection_slug}",
298
+ "DESCRIPTION": f"Allows this app to communicate with external services for connection '{connection_slug}'",
299
+ "HOST_PORTS": network_addresses,
300
+ }
301
+ if privatelink_addresses:
302
+ eai_spec_props["PRIVATE_HOST_PORTS"] = privatelink_addresses
303
+ _call_proc(
304
+ session,
305
+ "call PLUGIN.SET_EAI_SPECIFICATION(?, PARSE_JSON(?))",
306
+ [eai_spec_name, json.dumps(eai_spec_props)],
307
+ )
308
+
309
+ # (9) SI application specification — delegate to SET_SI_SPECIFICATION (OAuth only).
310
+ if si_spec_name:
311
+ op2 = oauth_parameters
312
+ grant_uc = op2.oauth_grant.upper()
313
+ # Include the alternating suffix letter so the edit-flow spec gets a distinct label.
314
+ si_spec_alt = si_spec_name[-1]
315
+ si_spec_props = {
316
+ "LABEL": f"OAuth integration for connection: {connection_slug} ({si_spec_alt})",
317
+ "DESCRIPTION": f"Allows this app to use an OAuth security integration for connection '{connection_slug}'",
318
+ "OAUTH_TYPE": grant_uc,
319
+ }
320
+ if op2.oauth_token_endpoint:
321
+ si_spec_props["OAUTH_TOKEN_ENDPOINT"] = op2.oauth_token_endpoint
322
+ if grant_uc == 'AUTHORIZATION_CODE' and op2.oauth_authorization_endpoint:
323
+ si_spec_props["OAUTH_AUTHORIZATION_ENDPOINT"] = op2.oauth_authorization_endpoint
324
+ if op2.oauth_allowed_scopes:
325
+ si_spec_props["OAUTH_ALLOWED_SCOPES"] = op2.oauth_allowed_scopes
326
+ _call_proc(
327
+ session,
328
+ "call PLUGIN.SET_SI_SPECIFICATION(?, PARSE_JSON(?))",
329
+ [si_spec_name, json.dumps(si_spec_props)],
330
+ )
331
+
332
+ return {
333
+ "success": True,
334
+ "data": {
335
+ "connection_slug": connection_slug,
336
+ "external_access_integration_name": eai_name,
337
+ "network_rule_name": network_rule_fqn,
338
+ "network_rule_name_privatelink": privatelink_rule_fqn,
339
+ "oauth_security_integration_name": oauth_si_name,
340
+ "oauth_secret_name": oauth_secret_fqn,
341
+ "oauth_secret_configuration_name": oauth_secret_config_name,
342
+ "other_secrets_name": other_secrets_fqn,
343
+ "external_access_integration_spec_name": eai_spec_name,
344
+ "security_integration_spec_name": si_spec_name,
345
+ },
346
+ }
347
+ except Exception as exception:
348
+ log_exception(exception, logger)
349
+ return {
350
+ "success": False,
351
+ "error": f"SET_CONNECTION_OBJECTS: {str(exception)}",
352
+ }
353
+ $$
354
+ ;
355
+
356
+ grant usage on procedure PLUGIN.SET_CONNECTION_OBJECTS(OBJECT)
357
+ to application role OMNATA_MANAGEMENT;
@@ -1,35 +0,0 @@
1
- create or replace procedure PLUGIN.CREATE_GENERIC_SECRET_OBJECT(SECRET_NAME VARCHAR,SECRET_CONTENTS VARCHAR)
2
- returns object
3
- language javascript
4
- COMMENT = $$
5
- Creates a generic secret object.
6
- $$
7
- execute as owner
8
- as
9
- $$
10
- try{
11
- snowflake.createStatement( {
12
- sqlText: `CREATE OR REPLACE SECRET IDENTIFIER(?) TYPE = GENERIC_STRING SECRET_STRING = ?`,
13
- binds:[SECRET_NAME,SECRET_CONTENTS]
14
- } ).execute();
15
- snowflake.createStatement( {
16
- sqlText: `grant usage on secret IDENTIFIER(?) to application role OMNATA_MANAGEMENT`,
17
- binds:[SECRET_NAME]
18
- } ).execute();
19
- return {
20
- "success": true,
21
- "data": null
22
- }
23
- }
24
- catch(e){
25
- return {
26
- "success": false,
27
- "error": `CREATE_GENERIC_SECRET_OBJECT: ${String(e)}`
28
- }
29
- }
30
- $$
31
- ;
32
-
33
- grant usage on procedure PLUGIN.CREATE_GENERIC_SECRET_OBJECT(VARCHAR,VARCHAR)
34
- to application role OMNATA_MANAGEMENT;
35
-
@@ -1,55 +0,0 @@
1
- create or replace procedure PLUGIN.CREATE_GENERIC_SECRET_OBJECT_FROM_EXISTING(SECRET_NAME VARCHAR,SECRET_TO_CLONE VARCHAR,KEYS_TO_INCLUDE ARRAY)
2
- returns object
3
- language javascript
4
- COMMENT = $$
5
- Creates a generic secret object, using an existing object as a starting point.
6
- $$
7
- execute as owner
8
- as
9
- $$
10
- try{
11
- // retrieve the existing secrets
12
- var results = snowflake.createStatement( {
13
- sqlText: `call RETRIEVE_SECRETS(null,?)`,
14
- binds:[SECRET_TO_CLONE]
15
- } ).execute();
16
- results.next();
17
- var procResult = results.getColumnValue(1);
18
- if (procResult.success===false){
19
- throw procResult.error;
20
- }
21
- var existingSecrets = procResult.data;
22
- if (KEYS_TO_INCLUDE != null){
23
- // pick out the specific keys from the KEYS_TO_INCLUDE array
24
- existingSecrets = KEYS_TO_INCLUDE.reduce((acc,key) => {
25
- acc[key] = existingSecrets[key];
26
- return acc;
27
- }, {})
28
- }
29
- // create the secret object by calling the regular proc
30
- var results = snowflake.createStatement( {
31
- sqlText: `call CREATE_GENERIC_SECRET_OBJECT(?,?)`,
32
- binds:[SECRET_NAME,JSON.stringify(existingSecrets)]
33
- } ).execute();
34
- results.next();
35
- var procResult = results.getColumnValue(1);
36
- if (procResult.success===false){
37
- throw procResult.error;
38
- }
39
- return {
40
- "success": true,
41
- "data": null
42
- }
43
- }
44
- catch(e){
45
- return {
46
- "success": false,
47
- "error": `CREATE_GENERIC_SECRET_OBJECT_FROM_EXISTING: ${String(e)}`
48
- }
49
- }
50
- $$
51
- ;
52
-
53
- grant usage on procedure PLUGIN.CREATE_GENERIC_SECRET_OBJECT_FROM_EXISTING(VARCHAR,VARCHAR,ARRAY)
54
- to application role OMNATA_MANAGEMENT;
55
-