Skip to content

Commit 2c7f5a3

Browse files
authored
fix: enable rustls-backed Postgres TLS connections (#729)
1 parent a805c22 commit 2c7f5a3

File tree

4 files changed

+88
-5
lines changed

4 files changed

+88
-5
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ dir-test = "0.4.1"
4444
prost = "0.13.5"
4545
prost-reflect = "0.15.3"
4646
protox = "0.8.0"
47-
sqlx = { version = "0.8.2", features = ["runtime-tokio", "runtime-async-std", "postgres", "json"] }
47+
sqlx = { version = "0.8.2", features = ["runtime-tokio-rustls", "runtime-async-std-rustls", "postgres", "json"] }
4848
syn = { version = "1.0.109", features = ["full"] }
4949
termcolor = "1.4.1"
5050
test-log = "0.2.17"

Dockerfile

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@ FROM postgres:15
22

33
# Install build dependencies
44
RUN apt-get update && \
5-
apt-get install -y postgresql-server-dev-15 gcc make git curl pkg-config libssl-dev libclang-dev clang libicu-dev && \
5+
apt-get install -y postgresql-server-dev-15 gcc make git curl pkg-config libssl-dev libclang-dev clang libicu-dev openssl && \
6+
mkdir -p /etc/postgresql/ssl && \
7+
openssl req -x509 -newkey rsa:2048 -sha256 -days 3650 -nodes \
8+
-subj "/CN=localhost" \
9+
-keyout /etc/postgresql/ssl/server.key \
10+
-out /etc/postgresql/ssl/server.crt && \
11+
chmod 600 /etc/postgresql/ssl/server.key && \
12+
chmod 644 /etc/postgresql/ssl/server.crt && \
13+
chown postgres:postgres /etc/postgresql/ssl/server.key /etc/postgresql/ssl/server.crt && \
614
# Install plpgsql_check (C extension - simple make install)
715
# Pin to v2.7.11 for stability with PG15
816
cd /tmp && \
@@ -24,12 +32,12 @@ RUN apt-get update && \
2432
git clone --depth 1 https://github.com/pmpetit/pglinter.git && \
2533
cd pglinter && \
2634
cargo pgrx install --pg-config $(which pg_config) --release && \
27-
# Cleanup Rust and build dependencies
35+
# Cleanup Rust toolchains and temporary sources
2836
rm -rf /tmp/pglinter $HOME/.cargo $HOME/.rustup && \
29-
apt-get remove -y gcc make git curl pkg-config libssl-dev libclang-dev clang libicu-dev && \
30-
apt-get autoremove -y && \
3137
rm -rf /var/lib/apt/lists/*
3238

39+
RUN printf "\nssl = on\nssl_cert_file = '/etc/postgresql/ssl/server.crt'\nssl_key_file = '/etc/postgresql/ssl/server.key'\n" >> /usr/share/postgresql/postgresql.conf.sample
40+
3341
# Add initialization script for extensions
3442
# Create extensions in a dedicated 'extensions' schema to avoid triggering extensionInPublic lint
3543
# Create in template1 so they're available in all new databases (for SQLx tests)

crates/pgls_cli/tests/assert_check.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
use assert_cmd::cargo_bin_cmd;
22
use insta::assert_snapshot;
3+
#[cfg(target_os = "linux")]
4+
use sqlx::PgPool;
35
use std::path::Path;
6+
#[cfg(target_os = "linux")]
7+
use std::path::PathBuf;
48
use std::process::ExitStatus;
59
const CONFIG_PATH: &str = "tests/fixtures/postgres-language-server.jsonc";
610

@@ -125,6 +129,75 @@ fn check_directory_traversal_snapshot() {
125129
));
126130
}
127131

132+
#[cfg(target_os = "linux")]
133+
fn get_database_url(pool: &PgPool) -> String {
134+
let opts = pool.connect_options();
135+
format!(
136+
"postgres://postgres:postgres@{}:{}/{}",
137+
opts.get_host(),
138+
opts.get_port(),
139+
opts.get_database().unwrap_or("postgres")
140+
)
141+
}
142+
143+
#[cfg(target_os = "linux")]
144+
fn create_temp_sql_file(contents: &str) -> PathBuf {
145+
let path = std::env::temp_dir().join(format!(
146+
"pgls-tls-{}-{}.sql",
147+
std::process::id(),
148+
std::time::SystemTime::now()
149+
.duration_since(std::time::UNIX_EPOCH)
150+
.expect("system clock should be after unix epoch")
151+
.as_nanos()
152+
));
153+
154+
std::fs::write(&path, contents).expect("failed to write temporary SQL file");
155+
path
156+
}
157+
158+
#[cfg(target_os = "linux")]
159+
#[sqlx::test(migrator = "pgls_test_utils::MIGRATIONS")]
160+
async fn check_accepts_tls_connection_strings(test_db: PgPool) {
161+
let sql_file = create_temp_sql_file("select 1;\n");
162+
let connection_string = format!(
163+
"{}?sslmode=require&channel_binding=require",
164+
get_database_url(&test_db)
165+
);
166+
167+
let mut cmd = cargo_bin_cmd!("postgres-language-server");
168+
let output = cmd
169+
.args([
170+
"check",
171+
sql_file
172+
.to_str()
173+
.expect("temporary SQL file path should be valid UTF-8"),
174+
"--connection-string",
175+
&connection_string,
176+
"--log-level",
177+
"none",
178+
])
179+
.output()
180+
.expect("failed to run CLI");
181+
182+
let stdout = String::from_utf8_lossy(&output.stdout);
183+
let stderr = String::from_utf8_lossy(&output.stderr);
184+
185+
assert!(
186+
output.status.success(),
187+
"expected TLS-backed check to succeed\nstdout:\n{stdout}\nstderr:\n{stderr}"
188+
);
189+
assert!(
190+
!stdout.contains("TLS upgrade required") && !stderr.contains("TLS upgrade required"),
191+
"TLS support error should not appear\nstdout:\n{stdout}\nstderr:\n{stderr}"
192+
);
193+
assert!(
194+
stdout.contains("Checked 1 file"),
195+
"expected successful CLI output\nstdout:\n{stdout}\nstderr:\n{stderr}"
196+
);
197+
198+
std::fs::remove_file(sql_file).expect("failed to remove temporary SQL file");
199+
}
200+
128201
fn run_check(args: &[&str]) -> String {
129202
let mut full_args = vec!["--config-path", CONFIG_PATH, "--log-level", "none"];
130203
full_args.extend_from_slice(args);

0 commit comments

Comments
 (0)