strata-cli 0.1.19 → 0.1.20

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7cdf350ee694b8dfcac291d7aeb7f13cc3f0cec82535f56e61fe9408ffbcc6f7
4
- data.tar.gz: eb05515761938400bbad1961110569d46db0a9f6e118b3b091bdcf42c62f0b34
3
+ metadata.gz: 28b84442e2989e729c2f9241c4af084eed8b346f62267d00c7bc27f3a4cb7d5d
4
+ data.tar.gz: b3e436e5055ea145a030bd88e27fb7b11ec1f6965886a65cb94aeee26ba34f5f
5
5
  SHA512:
6
- metadata.gz: a9300ece338d7b455ddf1db63658e95820a96dea1807493e0cfbcbb7931d19d9d5ddef6b5953c16cf083bc28416099a64f3cf5b5263c68b44b5981a018c83487
7
- data.tar.gz: f5c4575f2ab7415300e22794efedada1cf43bd77da69d9a4d04dd9abb84ac87da109b0b28f911ed2e6e74ad06532ee6b57eed1c1b2dd7693d9da14abbe38147b
6
+ metadata.gz: 022cb33cdb574fd26548b9239ea39520e196f019a5f5d1808e84acf19e15f22a92d7acf550b70d729a799d4a389e48cd66950fa616809afbb96f569f87c00720
7
+ data.tar.gz: f3bd0b00b86ddae87a55262f15d49665606fde89211d3bd2fc5ec9ca33233b998253e5f949d170052a3c8d7ee210c5f6187ed38ed9603487cd5c218fdd9ed89b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.20] - 2026-09-30
4
+
5
+ ### Changed
6
+
7
+ - **File-based secrets stored as contents**: `strata ds auth` now reads a BigQuery service account keyfile and saves only its `client_email` and `private_key`, and reads a Snowflake key-pair private key file and saves the PEM text, so a remote Strata server never needs the file. `.strata` blocks are written with YAML serialisation to hold multi-line values. Requires dwh 0.6.2 and a server with encrypted `password`/`private_key` columns.
8
+ - **`strata ds auth --remote` removed**: the flag was documented but never implemented; credentials reach the server through `strata deploy`.
9
+
10
+ ### Fixed
11
+
12
+ - `strata init -d ADAPTER` wrote a bare `ADAPTER:` node with no config, which then broke `ds list`, `ds auth`, and `audit`. It now renders the commented adapter template again, and templates were added for sqlite, redshift, clickhouse, and bigquery.
13
+
3
14
  ## [0.1.19] - 2026-09-30
4
15
 
5
16
  ### Added
data/README.md CHANGED
@@ -364,6 +364,8 @@ ai_api_key: your-ai-key
364
364
 
365
365
  **Security:** The `.strata` file automatically has restrictive permissions (0600) for security.
366
366
 
367
+ File-based secrets are stored as contents, not paths: a BigQuery keyfile becomes `client_email` + `private_key`, and a Snowflake key-pair `private_key` holds the PEM text. Credentials travel to the server with each deploy and are stored encrypted there.
368
+
367
369
  ### Authentication
368
370
 
369
371
  You don't need to create an API key manually. When no key is configured, `strata deploy` (and `strata project sample`) asks how you'd like to authenticate:
@@ -441,7 +443,7 @@ my_bigquery:
441
443
  dataset: analytics
442
444
  ```
443
445
 
444
- Run `strata ds auth my_bigquery` to save a service account `keyfile` path in `.strata`, or leave it blank to use `gcloud auth application-default login`.
446
+ Run `strata ds auth my_bigquery` and give the service account JSON keyfile path: only its `client_email` and `private_key` are saved in `.strata`, so the server never needs the file.
445
447
 
446
448
  ## Supported Data Warehouse Adapters
447
449
 
@@ -457,7 +459,7 @@ Run `strata ds auth my_bigquery` to save a service account `keyfile` path in `.s
457
459
  - **Databricks** - Databricks SQL warehouse support
458
460
  - **ClickHouse** - ClickHouse HTTP/native SQL support
459
461
  - **SQLite** - SQLite database support
460
- - **BigQuery** - Google BigQuery support (service account keyfile or Application Default Credentials)
462
+ - **BigQuery** - Google BigQuery support (service account key)
461
463
 
462
464
  ## Security
463
465
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "yaml"
4
+ require "json"
4
5
  require "tty-prompt"
5
6
 
6
7
  module Strata
@@ -39,7 +40,7 @@ module Strata
39
40
  credentials["personal_access_token"] = @prompt.ask("Enter Personal Access Token:")
40
41
  when "kp"
41
42
  credentials["username"] = @prompt.ask("Enter Username:")
42
- credentials["private_key"] = @prompt.ask("Enter Private Key Absolute Path:")
43
+ credentials["private_key"] = read_secret_file("Private key path (the PEM contents are stored):")
43
44
  end
44
45
  when "athena"
45
46
  credentials["access_key_id"] = @prompt.ask("AWS Access Key ID:")
@@ -51,7 +52,7 @@ module Strata
51
52
  when "clickhouse"
52
53
  credentials["password"] = @prompt.mask("Enter Password (leave blank if none):")
53
54
  when "bigquery"
54
- credentials["keyfile"] = @prompt.ask("Service account keyfile path (leave blank for Application Default Credentials):")
55
+ credentials.merge!(bigquery_service_account)
55
56
  else
56
57
  if required?
57
58
  unless %w[postgres mysql trino sqlserver].include?(adapter)
@@ -70,12 +71,11 @@ module Strata
70
71
 
71
72
  def write_local(ds_key, context)
72
73
  context.gsub_file Configuration::STRATA_CONFIG_FILE, Utils.yaml_block_matcher(ds_key), ""
73
- creds = "#{ds_key}:"
74
- credentials.each do |key, val|
75
- creds << "\n #{key}: #{val}" unless val.nil? || val.empty?
76
- end
74
+ values = credentials.reject { |_, val| val.nil? || val.to_s.empty? }
77
75
 
78
- context.append_to_file Configuration::STRATA_CONFIG_FILE, creds
76
+ # YAML.dump so multi-line values (PEM keys) become indented block scalars
77
+ # that yaml_block_matcher can still find and replace on the next auth.
78
+ context.append_to_file Configuration::STRATA_CONFIG_FILE, YAML.dump({ds_key => values}).delete_prefix("---\n")
79
79
 
80
80
  # Set restrictive permissions (read/write for owner only)
81
81
  strata_file = Configuration::STRATA_CONFIG_FILE
@@ -83,6 +83,43 @@ module Strata
83
83
  rescue Errno::EACCES => e
84
84
  raise Strata::CommandError, "Permission denied setting permissions on #{strata_file}: #{e.message}"
85
85
  end
86
+
87
+ private
88
+
89
+ # Asks for a file path and returns the file's contents so the server never
90
+ # needs the file itself. Blank returns nil; an answer that is not a path is
91
+ # kept as typed, which allows pasting the value directly.
92
+ def read_secret_file(question)
93
+ answer = @prompt.ask(question).to_s.strip
94
+ return nil if answer.empty?
95
+
96
+ File.exist?(answer) ? File.read(answer) : answer
97
+ end
98
+
99
+ # Reads the Google service account JSON once and keeps only the two fields
100
+ # needed to authenticate. The server has no other way to reach BigQuery,
101
+ # so without the file nothing is saved and the user is told to come back.
102
+ def bigquery_service_account
103
+ path = @prompt.ask("Service account keyfile path:").to_s.strip
104
+ if path.empty?
105
+ say " No keyfile given, so no BigQuery credentials were saved. Run `strata ds auth <key>` with the service account keyfile before deploying.", :yellow
106
+ return {}
107
+ end
108
+
109
+ key = JSON.parse(File.read(path))
110
+ unless key["type"] == "service_account" && key["client_email"] && key["private_key"]
111
+ raise Strata::CommandError, "#{path} is not a service account keyfile (needs type, client_email and private_key)"
112
+ end
113
+
114
+ expected = @datasource_config["project_id"]
115
+ if expected && key["project_id"] && expected != key["project_id"]
116
+ say " Warning: keyfile project '#{key["project_id"]}' differs from datasources.yml project_id '#{expected}'", :yellow
117
+ end
118
+
119
+ key.slice("client_email", "private_key")
120
+ rescue Errno::ENOENT, JSON::ParserError => e
121
+ raise Strata::CommandError, "Could not read service account keyfile #{path}: #{e.message}"
122
+ end
86
123
  end
87
124
  end
88
125
  end
@@ -2,13 +2,12 @@ Example to set local credentials for a datasource with key games_dwh:
2
2
 
3
3
  strata ds auth games_dwh
4
4
 
5
- Example to set remote credentials for the same datasource:
6
-
7
- strata ds auth games_dwh -r
8
-
9
- Local credentials are saved in the projects .strata file. This will should not
10
- be checked into git.
11
-
12
- Remote credentials will securely send the credentials to the Strata server. This is
13
- not requires for some modes like OAuth. In that case each user will be prompted to
14
- go through the OAuth flow. Not all adapters support OAuth.
5
+ Credentials are saved in the project's .strata file, which must not be
6
+ checked into git. They are sent to the Strata server with each deploy and
7
+ stored encrypted there.
8
+
9
+ File-based secrets are stored as contents, not paths, so the server never
10
+ needs the file: for BigQuery, give the service account JSON keyfile path and
11
+ only its client_email and private_key are kept; for Snowflake key-pair auth, give the
12
+ private key path and the PEM contents are kept. OAuth modes need no local
13
+ credentials; each user goes through the OAuth flow instead.
@@ -27,8 +27,12 @@ module Strata
27
27
  @ds_key = get_unique_ds_key
28
28
  Output.print_status(:adapter, "adding #{adapter} config to datasources", type: :warning, context: self)
29
29
 
30
- # Interactive mode: write config directly from prompts
31
- config_yaml = {@ds_key => options[:config]}.to_yaml.sub(/^---\n/, "\n")
30
+ # `ds add` passes prompted config; `init -d` renders the commented adapter template.
31
+ config_yaml = if options[:config]
32
+ {@ds_key => options[:config]}.to_yaml.sub(/^---\n/, "\n")
33
+ else
34
+ "\n#{render_template("adapters/#{adapter}.yml")}"
35
+ end
32
36
  append_to_file pathify("datasources.yml"), config_yaml
33
37
  end
34
38
 
@@ -0,0 +1,29 @@
1
+ # Datasource key should be unique in the Project
2
+ <%= @ds_key %>:
3
+ # This is the display name of this datasource
4
+ name: MYDATASOURCENAME
5
+ # Optional description to provide more information in the UI
6
+ description: This DS is the warm tier of our Product Domain
7
+
8
+ # Required. Should be one of hot, warm, or cold. Helps the Query engine
9
+ # prioritize a datasource when multiple can handle the request.
10
+ tier: warm
11
+
12
+ # A valid supported adapter
13
+ adapter: bigquery
14
+
15
+ # default client name sent to the db
16
+ client_name: Strata
17
+
18
+ # Max allowed time a query can run on this Datasource before manual time out
19
+ query_timeout: 3600
20
+
21
+ # Required: GCP project id
22
+ project_id: my-gcp-project
23
+
24
+ # Required: Default dataset for unqualified table names
25
+ dataset: analytics
26
+
27
+ # Authenticate with a service account keyfile by running:
28
+ # `strata ds auth <%= @ds_key %>`
29
+ # keyfile:
@@ -0,0 +1,39 @@
1
+ # Datasource key should be unique in the Project
2
+ <%= @ds_key %>:
3
+ # This is the display name of this datasource
4
+ name: MYDATASOURCENAME
5
+ # Optional description to provide more information in the UI
6
+ description: This DS is the hot tier of our Product Domain
7
+
8
+ # Required. Should be one of hot, warm, or cold. Helps the Query engine
9
+ # prioritize a datasource when multiple can handle the request.
10
+ tier: hot
11
+
12
+ # A valid supported adapter
13
+ adapter: clickhouse
14
+
15
+ # default client name sent to the db
16
+ client_name: Strata
17
+
18
+ # Max allowed time a query can run on this Datasource before manual time out
19
+ query_timeout: 3600
20
+
21
+ # Required: http or https
22
+ protocol: http
23
+
24
+ # Required: ClickHouse server host
25
+ host: localhost
26
+
27
+ # Optional: HTTP port (default: 8123)
28
+ port: 8123
29
+
30
+ # Required: Database name
31
+ database: test_db
32
+
33
+ # Required: Username for connection
34
+ username: default
35
+
36
+ # To set the password securely please run:
37
+ # `strata ds auth <%= @ds_key %>`
38
+ # This command will save your credentials to the .strata global or local file.
39
+ # password:
@@ -0,0 +1,39 @@
1
+ # Datasource key should be unique in the Project
2
+ <%= @ds_key %>:
3
+ # This is the display name of this datasource
4
+ name: MYDATASOURCENAME
5
+ # Optional description to provide more information in the UI
6
+ description: This DS is the warm tier of our Product Domain
7
+
8
+ # Required. Should be one of hot, warm, or cold. Helps the Query engine
9
+ # prioritize a datasource when multiple can handle the request.
10
+ tier: warm
11
+
12
+ # A valid supported adapter
13
+ adapter: redshift
14
+
15
+ # default client name sent to the db
16
+ client_name: Strata
17
+
18
+ # Max allowed time a query can run on this Datasource before manual time out
19
+ query_timeout: 3600
20
+
21
+ # Required: Redshift cluster endpoint
22
+ host: mycluster.abc123.us-east-1.redshift.amazonaws.com
23
+
24
+ # Optional: Port number (default: 5439)
25
+ port: 5439
26
+
27
+ # Required: Database name
28
+ database: dev
29
+
30
+ # Required: Username for connection
31
+ username: awsuser
32
+
33
+ # Optional: Schema name (default: public)
34
+ schema: public
35
+
36
+ # To set the password securely please run:
37
+ # `strata ds auth <%= @ds_key %>`
38
+ # This command will save your credentials to the .strata global or local file.
39
+ # password:
@@ -0,0 +1,22 @@
1
+ # Datasource key should be unique in the Project
2
+ <%= @ds_key %>:
3
+ # This is the display name of this datasource
4
+ name: MYDATASOURCENAME
5
+ # Optional description to provide more information in the UI
6
+ description: This DS is the hot tier of our Product Domain
7
+
8
+ # Required. Should be one of hot, warm, or cold. Helps the Query engine
9
+ # prioritize a datasource when multiple can handle the request.
10
+ tier: hot
11
+
12
+ # A valid supported adapter
13
+ adapter: sqlite
14
+
15
+ # default client name sent to the db
16
+ client_name: Strata
17
+
18
+ # Max allowed time a query can run on this Datasource before manual time out
19
+ query_timeout: 600
20
+
21
+ # Required: Path to the SQLite database file
22
+ file: ./data/warehouse.db
@@ -199,7 +199,7 @@ module Strata
199
199
  when :trino
200
200
  "Notes:\n- 'trino-client' is pure Ruby; no system libraries required."
201
201
  when :bigquery
202
- "Notes:\n- 'google-cloud-bigquery' is pure Ruby; no system libraries required.\n- Authenticate with a service account keyfile or `gcloud auth application-default login`."
202
+ "Notes:\n- 'google-cloud-bigquery' is pure Ruby; no system libraries required.\n- Authenticate with a service account keyfile (strata ds auth)."
203
203
  when :duckdb
204
204
  "Notes:\n- See https://github.com/suketa/ruby-duckdb"
205
205
  else
@@ -115,7 +115,10 @@ module Strata
115
115
  say " Databricks uses OAuth M2M with service principal credentials (client ID + client secret).", :cyan
116
116
  end
117
117
  if adapter == "bigquery"
118
- say " BigQuery uses a service account JSON keyfile, or gcloud Application Default Credentials if left blank.", :cyan
118
+ say " BigQuery: give the service account JSON keyfile path; only its client_email and private_key are stored.", :cyan
119
+ end
120
+ if adapter == "snowflake"
121
+ say " Snowflake key-pair: give the private key path; the PEM contents are stored, not the path.", :cyan
119
122
  end
120
123
  say ""
121
124
  creds.collect
@@ -143,7 +146,6 @@ module Strata
143
146
 
144
147
  desc "auth DS_KEY", "Set credentials for the given datasource key (DS_KEY)."
145
148
  long_desc_from_file "datasource/auth"
146
- method_option :remote, aliases: ["r"], type: :boolean, desc: "Set credentials on remote server"
147
149
  def auth(ds_key)
148
150
  unless datasources[ds_key]
149
151
  say "Error: Datasource '#{ds_key}' not found in datasources.yml", :red
@@ -165,7 +167,10 @@ module Strata
165
167
  say " Databricks uses OAuth M2M with service principal credentials (client ID + client secret).", :cyan
166
168
  end
167
169
  if adapter == "bigquery"
168
- say " BigQuery uses a service account JSON keyfile, or gcloud Application Default Credentials if left blank.", :cyan
170
+ say " BigQuery: give the service account JSON keyfile path; only its client_email and private_key are stored.", :cyan
171
+ end
172
+ if adapter == "snowflake"
173
+ say " Snowflake key-pair: give the private key path; the PEM contents are stored, not the path.", :cyan
169
174
  end
170
175
  say ""
171
176
  creds.collect
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Strata
4
4
  module CLI
5
- VERSION = "0.1.19"
5
+ VERSION = "0.1.20"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: strata-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.19
4
+ version: 0.1.20
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ajo Abraham
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.6.0
19
+ version: 0.6.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.6.0
26
+ version: 0.6.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: aws-sdk-athena
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -274,12 +274,16 @@ files:
274
274
  - lib/strata/cli/generators/table.rb
275
275
  - lib/strata/cli/generators/templates/AGENTS.md
276
276
  - lib/strata/cli/generators/templates/adapters/athena.yml
277
+ - lib/strata/cli/generators/templates/adapters/bigquery.yml
278
+ - lib/strata/cli/generators/templates/adapters/clickhouse.yml
277
279
  - lib/strata/cli/generators/templates/adapters/databricks.yml
278
280
  - lib/strata/cli/generators/templates/adapters/druid.yml
279
281
  - lib/strata/cli/generators/templates/adapters/duckdb.yml
280
282
  - lib/strata/cli/generators/templates/adapters/mysql.yml
281
283
  - lib/strata/cli/generators/templates/adapters/postgres.yml
284
+ - lib/strata/cli/generators/templates/adapters/redshift.yml
282
285
  - lib/strata/cli/generators/templates/adapters/snowflake.yml
286
+ - lib/strata/cli/generators/templates/adapters/sqlite.yml
283
287
  - lib/strata/cli/generators/templates/adapters/sqlserver.yml
284
288
  - lib/strata/cli/generators/templates/adapters/trino.yml
285
289
  - lib/strata/cli/generators/templates/datasources.yml
@@ -344,7 +348,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
344
348
  - !ruby/object:Gem::Version
345
349
  version: '0'
346
350
  requirements: []
347
- rubygems_version: 3.6.7
351
+ rubygems_version: 3.6.9
348
352
  specification_version: 4
349
353
  summary: Command-line interface for the Strata Semantic Analytics System
350
354
  test_files: []