Skip to content

Commit 6e7f0b2

Browse files
authored
Merge pull request #196 from cipherstash/error-or-warn-if-encrypt-config-missing
Error or warn if encrypt config missing
2 parents 70d4b14 + c454963 commit 6e7f0b2

File tree

8 files changed

+377
-264
lines changed

8 files changed

+377
-264
lines changed

Cargo.lock

Lines changed: 308 additions & 243 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/errors.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Check the configured username and password are correct and can connect to the da
4848

4949
Check the database is using a supported authentication method.
5050

51-
CipherStash Proxy supportsseveral PostgreSQL password authentication methods:
51+
CipherStash Proxy supports several PostgreSQL password authentication methods:
5252

5353
- password
5454
- md5
@@ -178,7 +178,7 @@ An error occurred when attempting to type check the SQL statement.
178178
### Error message
179179

180180
```
181-
Statement could not be type checked: '{type-check-erro-message}'
181+
Statement could not be type checked: '{type-check-error-message}'
182182
```
183183

184184
### Notes
@@ -424,4 +424,4 @@ If using PEM-based configuration:
424424
Check that the certificate and private key are valid.
425425

426426

427-
<!-- ---------------------------------------------------------------------------------------------------- -->
427+
<!-- ---------------------------------------------------------------------------------------------------- -->

mise.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,17 @@ mise --env tcp run test:wait_for_postgres_to_quack --port 6432 --max-retries 20
318318
mise --env tcp run test:integration:migrate
319319
mise --env tcp run proxy:down
320320
321+
echo
322+
echo '###############################################'
323+
echo '# Test: Warning for missing encrypt config'
324+
echo '###############################################'
325+
echo
326+
327+
mise --env tcp run proxy:up proxy --extra-args "--detach --wait"
328+
mise --env tcp run test:wait_for_postgres_to_quack --port 6432 --max-retries 20
329+
mise --env tcp run test:integration:warn_missing_config
330+
mise --env tcp run proxy:down
331+
321332
echo
322333
echo '###############################################'
323334
echo '# Test: Python'

packages/cipherstash-proxy-integration/src/extended_protocol_error_messages.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ mod tests {
6666
if let Err(err) = result {
6767
let msg = err.to_string();
6868

69-
assert_eq!(msg, "db error: ERROR: Column 'encrypted_unconfigured' in table 'unconfigured' has no Encrypt configuration. For help visit https://github.com/cipherstash/proxy/blob/main/docs/errors.md#encrypt-unknown-column");
69+
// This is similar to below. The error message comes from tokio-postgres when Proxy
70+
// returns cs_encrypted_v1 and the client cannot convert to a string.
71+
// If mapping errors are enabled (enable_mapping_errors or CS_DEVELOPMENT__ENABLE_MAPPING_ERRORS),
72+
// then Proxy will return an error that says "Column X in table Y has no Encrypt configuration"
73+
assert_eq!(msg, "error serializing parameter 1: cannot convert between the Rust type `&str` and the Postgres type `cs_encrypted_v1`");
7074
} else {
7175
unreachable!();
7276
}

packages/cipherstash-proxy/src/postgresql/frontend.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ where
8686
let sent: u64 = bytes.len() as u64;
8787
counter!(CLIENTS_BYTES_RECEIVED_TOTAL).increment(sent);
8888

89-
if self.encrypt.is_passthrough() {
89+
if self.encrypt.config.mapping_disabled() {
9090
self.write_to_server(bytes).await?;
9191
return Ok(());
9292
}
@@ -785,8 +785,7 @@ where
785785
msg = "Configured column",
786786
column = ?identifier
787787
);
788-
let col = self.get_column(identifier)?;
789-
Some(col)
788+
self.get_column(identifier)?
790789
}
791790
_ => None,
792791
};
@@ -822,8 +821,7 @@ where
822821
column = ?identifier
823822
);
824823

825-
let col = self.get_column(identifier)?;
826-
Some(col)
824+
self.get_column(identifier)?
827825
}
828826
_ => None,
829827
};
@@ -850,7 +848,9 @@ where
850848
identifier = ?identifier
851849
);
852850
let col = self.get_column(identifier)?;
853-
literal_columns.push(Some(col));
851+
if col.is_some() {
852+
literal_columns.push(col);
853+
}
854854
}
855855
}
856856
}
@@ -860,9 +860,9 @@ where
860860

861861
///
862862
/// Get the column configuration for the Identifier
863-
/// Returns `EncryptError::UnknownColumn` if configuratiuon cannot be found for the Identified column
864-
///
865-
fn get_column(&self, identifier: Identifier) -> Result<Column, Error> {
863+
/// Returns `EncryptError::UnknownColumn` if configuration cannot be found for the Identified column
864+
/// if mapping enabled, and None if mapping is disabled. It'll log a warning either way.
865+
fn get_column(&self, identifier: Identifier) -> Result<Option<Column>, Error> {
866866
match self.encrypt.get_column_config(&identifier) {
867867
Some(config) => {
868868
debug!(
@@ -871,20 +871,24 @@ where
871871
msg = "Configured column",
872872
column = ?identifier
873873
);
874-
Ok(Column::new(identifier, config))
874+
Ok(Some(Column::new(identifier, config)))
875875
}
876876
None => {
877-
debug!(
877+
warn!(
878878
target: MAPPER,
879879
client_id = self.context.client_id,
880-
msg = "Configured column not found ",
880+
msg = "Configured column not found. Encryption configuration may have been deleted.",
881881
?identifier,
882882
);
883-
Err(EncryptError::UnknownColumn {
884-
table: identifier.table.to_owned(),
885-
column: identifier.column.to_owned(),
883+
if self.encrypt.config.mapping_errors_enabled() {
884+
Err(EncryptError::UnknownColumn {
885+
table: identifier.table.to_owned(),
886+
column: identifier.column.to_owned(),
887+
}
888+
.into())
889+
} else {
890+
Ok(None)
886891
}
887-
.into())
888892
}
889893
}
890894
}

tests/mise.tcp.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ CS_DATABASE__HOST = "postgres"
33
CS_DATABASE__PORT = "5532"
44
CS_PROMETHEUS__ENABLED = "true"
55
CS_LOG__LEVEL = "debug"
6+
CS_DEVELOPMENT__ENABLE_MAPPING_ERRORS = "false"
7+
CS_DEVELOPMENT__DISABLE_MAPPING = "false"

tests/python/tests/test_error_messsages.py renamed to tests/python/tests/test_error_messages.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,10 @@ def test_encrypted_column_with_no_configuration():
5454

5555
sql = "INSERT INTO unconfigured (id, encrypted_unconfigured) VALUES (%s, %s)"
5656

57-
with pytest.raises(psycopg.Error, match='#encrypt-unknown-column'):
57+
# This is EQL catching the error and returning it. Details are in docs/errors.md
58+
# When mapping errors are enabled, (enable_mapping_errors or CS_DEVELOPMENT__ENABLE_MAPPING_ERRORS)
59+
# Proxy will return an error that says "Column X in table Y has no Encrypt configuration"
60+
with pytest.raises(psycopg.Error, match=r"Encrypted column missing \w+ \(\w+\) field"):
5861
cursor.execute(sql, [id, val])
5962

6063

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env bash
2+
#MISE description="Test for warning about missing encrypt config. Run with mapping enabled and mapping error disabled"
3+
4+
# This test assumes that Proxy is running with mapping enabled with mapping error disabled
5+
6+
set -e
7+
8+
# Simulate delete config by renaming
9+
docker exec -i postgres"${CONTAINER_SUFFIX}" psql 'postgresql://cipherstash:password@proxy:6432/cipherstash' --command 'ALTER TABLE encrypted RENAME COLUMN encrypted_text TO unconfigured_text;' >/dev/null 2>&1
10+
11+
set +e
12+
TIMESTAMP=$(date -u +%Y-%m-%dT%H:%M:%SZ)
13+
docker exec -i postgres"${CONTAINER_SUFFIX}" psql 'postgresql://cipherstash:password@proxy:6432/cipherstash?sslmode=disable' --command 'SELECT unconfigured_text from encrypted' >/dev/null 2>&1
14+
LOG_CONTENT=$(docker logs --since "${TIMESTAMP}" proxy | tr "\n" " ")
15+
EXPECTED='Encryption configuration may have been deleted'
16+
17+
# Simulate delete config by renaming
18+
docker exec -i postgres"${CONTAINER_SUFFIX}" psql 'postgresql://cipherstash:password@proxy:6432/cipherstash' --command 'ALTER TABLE encrypted RENAME COLUMN unconfigured_text TO encrypted_text;' >/dev/null 2>&1
19+
20+
if echo "$LOG_CONTENT" | grep -v "${EXPECTED}"; then
21+
echo "error: did not see string in output: \"${EXPECTED}\""
22+
exit 1
23+
fi
24+

0 commit comments

Comments
 (0)