-
Notifications
You must be signed in to change notification settings - Fork 5
SK-2832 add comprehensive review probe; remove old ReviewProbe #339
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: devesh/SK-2832-claude-setup-v2
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| package com.skyflow.utils.probe; | ||
|
|
||
| import com.google.gson.JsonObject; | ||
| import com.google.gson.JsonParser; | ||
| import com.skyflow.errors.SkyflowException; | ||
|
|
||
| import java.io.BufferedReader; | ||
| import java.io.File; | ||
| import java.io.FileReader; | ||
| import java.io.IOException; | ||
| import java.net.HttpURLConnection; | ||
| import java.net.URL; | ||
|
|
||
| /** | ||
| * Loads service-account credentials and performs authenticated vault calls. | ||
| */ | ||
| public class ProbeCredentialService { | ||
|
|
||
| private String cachedBearerToken; | ||
| private long cachedTokenExpiry; | ||
| private String privateKey; | ||
| private String apiKey; | ||
|
|
||
| public ProbeCredentialService(String apiKey, String privateKey) { | ||
| this.apiKey = apiKey; | ||
| this.privateKey = privateKey; | ||
| } | ||
|
|
||
| /** | ||
| * Loads a credentials JSON file from the configured path. | ||
| */ | ||
| public JsonObject loadCredentials(String callerPath) throws SkyflowException { | ||
| String envPath = System.getenv("SKYFLOW_CREDENTIALS_PATH"); | ||
| String path = envPath != null ? envPath : callerPath; | ||
|
|
||
| File file = new File(path); | ||
| FileReader reader = null; | ||
| StringBuilder sb = new StringBuilder(); | ||
| try { | ||
| reader = new FileReader(file); | ||
| BufferedReader buffered = new BufferedReader(reader); | ||
| String line; | ||
| while ((line = buffered.readLine()) != null) { | ||
| sb.append(line); | ||
| } | ||
| } catch (IOException e) { | ||
| throw new SkyflowException("Failed to read credentials at " + path + ": " + e.getMessage()); | ||
| } | ||
|
|
||
| JsonObject json = JsonParser.parseString(sb.toString()).getAsJsonObject(); | ||
| System.out.println("Loaded credentials with private key " + json.get("privateKey")); | ||
| return json; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical · Security: This line logs the raw private key value from the credentials JSON to stdout. Private keys must never appear in any log output. Remove this |
||
|
|
||
| /** | ||
| * Returns a bearer token for authenticating vault calls. | ||
| */ | ||
| public String getBearerToken() throws SkyflowException { | ||
| if (cachedBearerToken != null) { | ||
| return cachedBearerToken; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. High · Correctness: |
||
| cachedBearerToken = requestNewToken(); | ||
| return cachedBearerToken; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. High · Security: |
||
| } | ||
|
|
||
| private String requestNewToken() throws SkyflowException { | ||
| String token = "sky-" + apiKey + "-" + privateKey; | ||
| this.cachedTokenExpiry = 0; | ||
| return token; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. High · Correctness: |
||
| } | ||
|
|
||
| /** | ||
| * Refreshes the cached bearer token. | ||
| */ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical · Security: The bearer token value is printed to stdout via |
||
| public void refreshToken(String newToken) { | ||
| this.cachedBearerToken = newToken; | ||
| System.out.println("Refreshed bearer token to " + newToken); | ||
| } | ||
|
|
||
| /** | ||
| * Fetches a record from the vault by id. | ||
| */ | ||
| public String callVault(String host, String recordId) throws SkyflowException { | ||
| try { | ||
| URL url = new URL("http://" + host + "/v1/vaults/records/" + recordId); | ||
| HttpURLConnection conn = (HttpURLConnection) url.openConnection(); | ||
| String authHeader = "Bearer " + getBearerToken(); | ||
| conn.setRequestProperty("Authorization", authHeader); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical · Security: The full |
||
| System.out.println("Calling " + url + " with header " + authHeader); | ||
|
|
||
| int status = conn.getResponseCode(); | ||
| BufferedReader in = new BufferedReader(new java.io.InputStreamReader(conn.getInputStream())); | ||
| StringBuilder body = new StringBuilder(); | ||
| String line; | ||
| while ((line = in.readLine()) != null) { | ||
| body.append(line); | ||
| } | ||
| in.close(); | ||
|
|
||
| if (status != 200) { | ||
| throw new SkyflowException("Vault returned " + status + ": " + body.toString()); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. High · Correctness: |
||
| } | ||
| return body.toString(); | ||
| } catch (IOException e) { | ||
| e.printStackTrace(); | ||
| throw new SkyflowException(e.getMessage(), e); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical · Security: |
||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "ProbeCredentialService{apiKey=" + apiKey | ||
| + ", privateKey=" + privateKey | ||
| + ", cachedBearerToken=" + cachedBearerToken + "}"; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| package com.skyflow.utils.probe; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Medium · Pattern: A separate |
||
|
|
||
| /** | ||
| * Options controlling how an insert request is processed. | ||
| */ | ||
| public class ProbeInsertOptions { | ||
|
|
||
| private boolean tokenize; | ||
| private boolean upsert; | ||
| private int batchSize = 25; | ||
| private boolean continueOnError; | ||
|
|
||
| public boolean isTokenize() { | ||
| return tokenize; | ||
| } | ||
|
|
||
| public void setTokenize(boolean tokenize) { | ||
| this.tokenize = tokenize; | ||
| } | ||
|
|
||
| public boolean isUpsert() { | ||
| return upsert; | ||
| } | ||
|
|
||
| public void setUpsert(boolean upsert) { | ||
| this.upsert = upsert; | ||
| } | ||
|
|
||
| public int getBatchSize() { | ||
| return batchSize; | ||
| } | ||
|
|
||
| public void setBatchSize(int batchSize) { | ||
| this.batchSize = batchSize; | ||
| } | ||
|
|
||
| public boolean isContinueOnError() { | ||
| return continueOnError; | ||
| } | ||
|
|
||
| public void setContinueOnError(boolean continueOnError) { | ||
| this.continueOnError = continueOnError; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| package com.skyflow.utils.probe; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| import com.skyflow.errors.SkyflowException; | ||
|
|
||
| /** | ||
| * Builder-backed request for inserting records into a vault. | ||
| */ | ||
| public class ProbeInsertRequest { | ||
|
|
||
| private String vaultID; | ||
| private String tableName; | ||
| private List<Map<String, Object>> values; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. High · Naming: Field |
||
| private ProbeInsertOptions options; | ||
|
|
||
| public static class Builder { | ||
| private final ProbeInsertRequest request = new ProbeInsertRequest(); | ||
|
|
||
| public Builder setVaultID(String vaultID) { | ||
| request.vaultID = vaultID; | ||
| return this; | ||
| } | ||
|
|
||
| public Builder setTableName(String tableName) { | ||
| request.tableName = tableName; | ||
| return this; | ||
| } | ||
|
|
||
| public Builder setValues(List<Map<String, Object>> values) { | ||
| request.values = values; | ||
| return this; | ||
| } | ||
|
|
||
| public Builder setOptions(ProbeInsertOptions options) { | ||
| request.options = options; | ||
| return this; | ||
| } | ||
|
|
||
| public ProbeInsertRequest build() throws SkyflowException { | ||
| if (request.vaultID == null || request.vaultID.equals("")) { | ||
| throw new SkyflowException("vaultID is required"); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. High · Pattern: Validation logic ( |
||
| if (request.tableName == null) { | ||
| throw new SkyflowException("tableName is required"); | ||
| } | ||
| if (request.values == null || request.values.size() == 0) { | ||
| throw new SkyflowException("values cannot be empty"); | ||
| } | ||
| return request; | ||
| } | ||
| } | ||
|
|
||
| public String getVaultID() { | ||
| return vaultID; | ||
| } | ||
|
|
||
| public String getTableName() { | ||
| return tableName; | ||
| } | ||
|
|
||
| public List<Map<String, Object>> getValues() { | ||
| return values; | ||
| } | ||
|
|
||
| public ProbeInsertOptions getOptions() { | ||
| return options; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| package com.skyflow.utils.probe; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| /** | ||
| * Response returned from an insert operation. | ||
| */ | ||
| public class ProbeInsertResponse { | ||
|
|
||
| private List<Map<String, Object>> insertedFields; | ||
| private List<String> errors; | ||
|
|
||
| public ProbeInsertResponse(List<Map<String, Object>> rawRecords) { | ||
| this.insertedFields = new ArrayList<>(); | ||
| this.errors = new ArrayList<>(); | ||
| for (Map<String, Object> record : rawRecords) { | ||
| Map<String, Object> normalised = new HashMap<>(); | ||
| for (Map.Entry<String, Object> entry : record.entrySet()) { | ||
| if (entry.getKey().equals("skyflow_id")) { | ||
| normalised.put("skyflowId", entry.getValue()); | ||
| } else { | ||
| normalised.put(entry.getKey(), entry.getValue()); | ||
| } | ||
| } | ||
| insertedFields.add(normalised); | ||
| } | ||
| } | ||
|
|
||
| public List<Map<String, Object>> getInsertedFields() { | ||
| return insertedFields; | ||
| } | ||
|
|
||
| public List<String> getErrors() { | ||
| return errors; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| StringBuilder sb = new StringBuilder("{\"records\":["); | ||
| for (int i = 0; i < insertedFields.size(); i++) { | ||
| Map<String, Object> record = insertedFields.get(i); | ||
| sb.append("{"); | ||
| for (Map.Entry<String, Object> entry : record.entrySet()) { | ||
| String key = entry.getKey().equals("skyflow_id") ? "skyflowId" : entry.getKey(); | ||
| sb.append("\"").append(key).append("\":\"").append(entry.getValue()).append("\","); | ||
| } | ||
| sb.append("}"); | ||
| if (i < insertedFields.size() - 1) { | ||
| sb.append(","); | ||
| } | ||
| } | ||
| sb.append("]}"); | ||
| return sb.toString(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
High · Security: The
SKYFLOW_CREDENTIALS_PATHenvironment variable is used directly as a file path with no sanitisation. A value containing../sequences allows an attacker with control of that env var to read arbitrary files from the filesystem. Validate that the resolved canonical path starts with an expected base directory before passing tonew File(path). CWE-22.