mirror of
https://github.com/google/nomulus
synced 2026-07-08 17:16:54 +00:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ab612ab23 | |||
| 403c7ad275 | |||
| 11d625b837 | |||
| 6a47287da7 | |||
| cdc0ffe831 | |||
| 7c23413d83 | |||
| fe222bbdcf | |||
| f770f6a46d | |||
| e071f5579c | |||
| 6080cd2f7a | |||
| 90f583910e | |||
| a85bf5c30a | |||
| dcfe939c38 | |||
| ae61922318 | |||
| 84e97aa2db | |||
| 4df4bf1489 | |||
| 9faabb0f1d | |||
| ea9d717378 | |||
| d1769b29ef | |||
| 14376953e5 | |||
| c13c9b53e3 | |||
| 1cd6026151 | |||
| 75524fd403 | |||
| a5b280838c | |||
| 5599a0eb3d | |||
| dde41078cd | |||
| 0030645b1a | |||
| c5abd2a7c9 | |||
| 5286b1a0dc | |||
| cd65a4c9d8 | |||
| beb7fcc16e | |||
| d68f3e5cc0 | |||
| 33d30ea6a1 | |||
| 00ee62f877 | |||
| 2bc07349a4 | |||
| 00522fb618 | |||
| ad992beff9 | |||
| ba91141505 | |||
| c1ce73db49 | |||
| 00ceb6a7df | |||
| c731b18304 | |||
| 5fd6e6cdaa |
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: java-ast-refactoring
|
||||
description: "AST-aware Java refactoring using OpenRewrite. Use when asked to structurally refactor Java code, change class names, change method signatures/overloads, replace builder patterns, modify annotations, or perform cross-file structural replacements. Note: Renaming fields or local variables/parameters is not supported natively via simple YAML recipes in the standard openrewrite modules."
|
||||
---
|
||||
|
||||
# AST-Aware Java Refactoring
|
||||
|
||||
This skill uses OpenRewrite to perform Abstract Syntax Tree (AST) based refactoring on Java codebases. This is highly preferred over text-based regex or python scripts because it understands Java semantics, correctly updates imports, and preserves formatting.
|
||||
|
||||
## Parameter and Field Renaming (Last Resort)
|
||||
|
||||
Because OpenRewrite's YAML recipes do not natively support simple variable or field renaming, a custom script is provided:
|
||||
```bash
|
||||
python3 .gemini/skills/java-ast-refactoring/scripts/safe_rename.py <filepath> <old_name> <new_name>
|
||||
```
|
||||
**CRITICAL:** Running this python script is a LAST RESORT. It is a regex-based token replacement that ignores strings and comments, but it lacks true AST understanding. ALWAYS prefer using OpenRewrite recipes (`rewrite.yml`) for structural changes like renaming classes, methods, or moving targets, as OpenRewrite correctly handles imports, types, and cross-file references safely.
|
||||
|
||||
## Usage
|
||||
|
||||
1. Create a `rewrite.yml` recipe file in the workspace root. Refer to `.gemini/skills/java-ast-refactoring/references/rewrite_recipes.md` for syntax.
|
||||
2. Execute the script:
|
||||
```bash
|
||||
./.gemini/skills/java-ast-refactoring/scripts/run_rewrite.sh rewrite.yml
|
||||
```
|
||||
3. The script will safely apply the AST transformations and then automatically run `./gradlew spotlessApply` and `./gradlew javaIncrementalFormatApply` on the modified files to automatically fix any Checkstyle line-length and import ordering issues caused by longer/shorter identifiers. Verify the output using `git diff`.
|
||||
4. **MANDATORY:** Always run `./gradlew build -x test` (or the equivalent compile task) after running OpenRewrite to ensure no compilation errors were introduced.
|
||||
|
||||
## Known Limitations & Troubleshooting
|
||||
* **Static Imports Dropped on Class Rename:** When using `ChangeType` to rename a class, OpenRewrite may sometimes drop static imports for fields/constants belonging to the old class instead of updating them to the new class. If compilation fails due to "cannot find symbol" for a constant after a class rename, manually restore the static import (e.g., `import static com.new.ClassName.CONSTANT;`).
|
||||
* **Continuous Improvement:** If any new issues or edge cases are found while running the refactoring (e.g., build failures, formatting issues, or missed transformations), you **MUST** proactively ask the user if you should permanently update this skill file (`SKILL.md`) and its accompanying scripts (`scripts/run_rewrite.sh`, `scripts/safe_rename.py`) to fix the issue for future use. Do not wait for the user to prompt you to fix the infrastructure.
|
||||
@@ -0,0 +1,82 @@
|
||||
# OpenRewrite Recipe Reference
|
||||
|
||||
OpenRewrite uses declarative YAML recipes to perform structural refactorings.
|
||||
|
||||
## Recipe Structure
|
||||
|
||||
A recipe file must have a `type`, a `name` (which you will activate), and a `recipeList` containing specific core recipes to execute sequentially.
|
||||
|
||||
```yaml
|
||||
type: specs.openrewrite.org/v1beta/recipe
|
||||
name: com.example.MyRefactoring
|
||||
recipeList:
|
||||
- <CoreRecipe>:
|
||||
<argument1>: <value>
|
||||
```
|
||||
|
||||
## Core Recipes for Common Operations
|
||||
|
||||
### 1. Change Method Name
|
||||
```yaml
|
||||
- org.openrewrite.java.ChangeMethodName:
|
||||
methodPattern: java.util.Collections emptyList()
|
||||
newMethodName: emptyList
|
||||
```
|
||||
|
||||
### 2. Change Method Target to Static
|
||||
Moves a method call to a new static method target. Useful for replacing custom utility methods with standard ones.
|
||||
```yaml
|
||||
- org.openrewrite.java.ChangeMethodTargetToStatic:
|
||||
methodPattern: google.registry.model.eppinput.EppInputs createDomain(java.lang.String, java.lang.String)
|
||||
fullyQualifiedTargetTypeName: google.registry.model.domain.DomainCommand.Create
|
||||
returnType: google.registry.model.domain.DomainCommand.Create.Builder
|
||||
```
|
||||
|
||||
### 3. Change Type (Rename/Move Class)
|
||||
Updates the class name and automatically updates all imports across the codebase.
|
||||
*Note: OpenRewrite occasionally drops `import static` references to fields inside the renamed class. Be prepared to manually restore them if a compilation error occurs.*
|
||||
```yaml
|
||||
- org.openrewrite.java.ChangeType:
|
||||
oldFullyQualifiedTypeName: org.joda.time.Instant
|
||||
newFullyQualifiedTypeName: java.time.Instant
|
||||
```
|
||||
|
||||
### 4. Remove Unused Imports
|
||||
```yaml
|
||||
- org.openrewrite.java.RemoveUnusedImports
|
||||
```
|
||||
|
||||
### 5. Change Annotation
|
||||
```yaml
|
||||
- org.openrewrite.java.ChangeAnnotation:
|
||||
annotationPattern: @org.junit.Ignore
|
||||
newAnnotation: @org.junit.jupiter.api.Disabled
|
||||
```
|
||||
|
||||
### 6. Remove Annotation
|
||||
```yaml
|
||||
- org.openrewrite.java.RemoveAnnotation:
|
||||
annotationPattern: @java.lang.SuppressWarnings("unchecked")
|
||||
```
|
||||
|
||||
### 7. Change Method Arguments
|
||||
Reorders or removes arguments based on a target signature. `newArgumentTemplate` uses 0-based indexing.
|
||||
```yaml
|
||||
- org.openrewrite.java.ChangeMethodAccessLevel:
|
||||
methodPattern: com.google.common.collect.ImmutableList of(..)
|
||||
newAccessLevel: protected
|
||||
```
|
||||
|
||||
### 8. Add Import
|
||||
```yaml
|
||||
- org.openrewrite.java.AddImport:
|
||||
type: java.util.List
|
||||
```
|
||||
|
||||
## Method Patterns
|
||||
OpenRewrite uses a specific pointcut expression language for `methodPattern`:
|
||||
* `[return-type] [fully-qualified-class-name] [method-name]([parameter-types])`
|
||||
* `*` matches any type.
|
||||
* `..` matches any number of parameters.
|
||||
* Example: `java.lang.String split(java.lang.String, int)`
|
||||
* Example: `* java.util.List add(..)`
|
||||
@@ -0,0 +1,80 @@
|
||||
#!/bin/bash
|
||||
# Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Wrapper script to dynamically execute OpenRewrite without modifying build.gradle
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <path-to-rewrite.yml>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RECIPE_FILE=$(realpath "$1")
|
||||
if [ ! -f "$RECIPE_FILE" ]; then
|
||||
echo "Error: Recipe file $RECIPE_FILE not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract the name of the recipe from the YAML to activate it
|
||||
RECIPE_NAME=$(grep -oP '(?<=name: ).*' "$RECIPE_FILE" | head -n 1)
|
||||
|
||||
if [ -z "$RECIPE_NAME" ]; then
|
||||
echo "Error: Could not extract 'name:' from $RECIPE_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
INIT_SCRIPT="rewrite-init.gradle"
|
||||
|
||||
cat << EOF > "$INIT_SCRIPT"
|
||||
initscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.openrewrite.rewrite:org.openrewrite.rewrite.gradle.plugin:7.33.0")
|
||||
}
|
||||
}
|
||||
|
||||
rootProject {
|
||||
apply plugin: org.openrewrite.gradle.RewritePlugin
|
||||
|
||||
rewrite {
|
||||
activeRecipe("$RECIPE_NAME")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
rewrite("org.openrewrite.recipe:rewrite-testing-frameworks:2.14.0")
|
||||
rewrite("org.openrewrite.recipe:rewrite-migrate-java:2.11.0")
|
||||
rewrite("org.openrewrite.recipe:rewrite-spring:5.7.0")
|
||||
}
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply plugin: org.openrewrite.gradle.RewritePlugin
|
||||
}
|
||||
EOF
|
||||
|
||||
# Copy the recipe file to the workspace root temporarily so OpenRewrite finds it
|
||||
cp "$RECIPE_FILE" ./rewrite.yml
|
||||
|
||||
echo "Executing OpenRewrite recipe: $RECIPE_NAME"
|
||||
./gradlew --init-script "$INIT_SCRIPT" rewriteRun --no-parallel --no-configuration-cache
|
||||
|
||||
echo "Running code formatters to fix Checkstyle line-length and import ordering..."
|
||||
./gradlew spotlessApply javaIncrementalFormatApply
|
||||
|
||||
# Clean up temporary files
|
||||
rm "$INIT_SCRIPT"
|
||||
rm ./rewrite.yml
|
||||
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
|
||||
def usage():
|
||||
print("Usage: python safe_rename.py <filepath> <old_name> <new_name>")
|
||||
print("Safely renames an identifier in a Java file, ignoring strings and comments.")
|
||||
sys.exit(1)
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 4:
|
||||
usage()
|
||||
|
||||
filepath = sys.argv[1]
|
||||
old_name = sys.argv[2]
|
||||
new_name = sys.argv[3]
|
||||
|
||||
if not os.path.exists(filepath):
|
||||
print(f"Error: File {filepath} not found.")
|
||||
sys.exit(1)
|
||||
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Regex to tokenize Java source safely.
|
||||
token_pattern = re.compile(
|
||||
r'(?P<string>"(?:\\.|[^"\\])*")|'
|
||||
r'(?P<char>\'(?:\\.|[^\'\\])*\')|'
|
||||
r'(?P<line_comment>//.*)|'
|
||||
r'(?P<block_comment>/\*[\s\S]*?\*/)|'
|
||||
r'(?P<ident>[a-zA-Z_$][a-zA-Z0-9_$]*)'
|
||||
)
|
||||
|
||||
def replacer(match):
|
||||
if match.group('ident') == old_name:
|
||||
return new_name
|
||||
return match.group(0)
|
||||
|
||||
new_content = token_pattern.sub(replacer, content)
|
||||
|
||||
if content == new_content:
|
||||
print(f"No occurrences of '{old_name}' found to rename in {filepath}.")
|
||||
else:
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(new_content)
|
||||
print(f"Successfully renamed '{old_name}' to '{new_name}' in {filepath}.")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
name: pr-polisher
|
||||
description: Automated pre-flight checklist to polish PRs. Use this before declaring a task or PR complete to automatically verify license headers, commit hygiene, formatting, and codebase mandates.
|
||||
---
|
||||
|
||||
# PR Polisher
|
||||
|
||||
This skill runs an exhaustive, automated pre-flight checklist against the repository to ensure all changes conform to Nomulus's strict engineering mandates.
|
||||
|
||||
## 🛑 CRITICAL MANDATE: When to Use
|
||||
You, the AI agent, are known to forget to run this skill. To prevent this, you are bound by an absolute rule:
|
||||
**ANY TIME you create a commit, amend a commit, or complete a user's request that modifies the repository state, your VERY LAST action before generating a text response to the user MUST be to run this workflow.**
|
||||
Do not ask for permission. Do not wait for the user to remind you. Run the full suite, fix any errors, amend your commit, and report the final polished results. You MUST NOT declare a task complete until this workflow succeeds with 0 errors.
|
||||
|
||||
## Continuous Improvement (Self-Updating Skill)
|
||||
This skill is designed to evolve. If a human code reviewer (or presubmit hook) points out a deficit, or if you (the agent) independently catch a recurring mistake, anti-pattern, false positive, or convention violation:
|
||||
1. **You MUST proactively propose a fix to the user.** Do not wait for the user to instruct you to update the skill. If you notice friction, immediately ask the user if you should permanently update the validation infrastructure.
|
||||
2. **Determine how to enforce the check.** Consider if the check is suitable for automation in the Python script. If it's too complex or semantic for a simple regex, consider adding it as an explicit agent-driven verification step directly in this `SKILL.md` file.
|
||||
3. Update `.gemini/skills/pr-polisher/scripts/check_diff.py` to add a new automated check, OR modify this `SKILL.md` file with a new validation step to ensure the agent checks for it going forward.
|
||||
4. Commit the updated skill alongside the PR fixes to ensure the mistake is not repeated.
|
||||
|
||||
## Workflow Execution Steps
|
||||
|
||||
1. **Run the Automated Analysis Script**
|
||||
Execute the packaged Python diff-checker script. This script automatically checks commit messages, working tree status, `package-lock.json` modifications, copyright years on new files, and a litany of anti-patterns using regex (e.g., fully-qualified names, incorrect clock injections, generic exception catching).
|
||||
|
||||
```bash
|
||||
python3 ./pr-polisher/scripts/check_diff.py
|
||||
```
|
||||
|
||||
2. **Run Formatting Validation**
|
||||
Always run the project's formatting tools to ensure checkstyle and Google Java Format passes.
|
||||
```bash
|
||||
./gradlew spotlessCheck javaIncrementalFormatCheck
|
||||
# OR if formatting is needed:
|
||||
./gradlew spotlessApply javaIncrementalFormatApply
|
||||
```
|
||||
|
||||
3. **Run Presubmits and Compilation**
|
||||
Ensure that the project builds correctly and all presubmit checks pass. Use scoped builds when possible to save time and avoid unwanted side effects (like modifying `console-webapp/package-lock.json`).
|
||||
```bash
|
||||
# Run presubmits
|
||||
./gradlew runPresubmits
|
||||
|
||||
# Verify compilation (use a scoped build if you only modified one module, e.g., :core)
|
||||
./gradlew :core:build -x test
|
||||
# Run standard test suite if modifying core
|
||||
./gradlew :core:standardTest
|
||||
```
|
||||
|
||||
4. **Verify PR Scope and Extraneous Files (Line-by-Line Inspection)**
|
||||
You must carefully review the entirety of your changes (`git diff HEAD^` or `git diff --cached`). Examine every single file and line changed to explicitly verify that the change *belongs* in this PR. You MUST look for and revert:
|
||||
* **Irrelevant changes:** Formatting or refactoring in files unrelated to the PR's core purpose.
|
||||
* **Accidental files:** Test output files, temp scripts, plan files (e.g., `codebase_review_plan.md`), scratchpads, or anything else generated during your workflow that shouldn't be committed.
|
||||
* **Unintended side effects:** Changes to configuration files like `package-lock.json` unless explicitly required.
|
||||
|
||||
5. **Verify Test Coverage Additions (Line-by-Line Inspection)**
|
||||
While looking at all the diffs, thoroughly check every single line to determine if any test changes or additions are necessary. If you have modified existing logic, added new branches, added a null check, or added new public methods, you MUST manually verify that the corresponding `Test.java` file covers these changes. If the test file or specific test cases do not exist, you must create them. A code review is not thorough if it only checks for compilation.
|
||||
|
||||
6. **Verify Commit Description Accuracy**
|
||||
Re-read your commit message (`git log -1 --pretty=format:%B`). Compare it directly against the actual diff (`git diff HEAD^`) to verify that it completely and accurately describes ONLY the changes present in the commit.
|
||||
* If the scope of the PR changed during prompting, you MUST update the commit message to reflect the final state of the code.
|
||||
* Ensure that the primary purpose of the PR is mentioned first, and that no irrelevant or outdated changes from previous attempts are listed.
|
||||
|
||||
7. **Address Errors, Amend, and Re-Run (Iterative Checking)**
|
||||
If any script throws an error, if scope was reduced, if the commit message was inaccurate, or if formatting changes were applied, you must stage those fixes and amend your commit:
|
||||
```bash
|
||||
git add -u
|
||||
git commit --amend # Or git commit --amend --no-edit if only files changed
|
||||
```
|
||||
**CRITICAL:** You must loop back to Step 1 and run `python3 ./pr-polisher/scripts/check_diff.py` again. Continue this loop of checking and amending until the script definitively returns `0 ERRORS`, the build/presubmits pass, and the working directory is perfectly clean. Do not assume your fixes worked without re-running the check.
|
||||
@@ -0,0 +1,330 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import subprocess
|
||||
import re
|
||||
import sys
|
||||
import datetime
|
||||
|
||||
# Color codes
|
||||
RED = "\03.3[91m"
|
||||
YELLOW = "\03.3[93m"
|
||||
GREEN = "\03.3[92m"
|
||||
RESET = "\03.3[0m"
|
||||
|
||||
errors_found = 0
|
||||
warnings_found = 0
|
||||
|
||||
def log_error(msg):
|
||||
global errors_found
|
||||
errors_found += 1
|
||||
print(f"{RED}[ERROR]{RESET} {msg}")
|
||||
|
||||
def log_warning(msg):
|
||||
global warnings_found
|
||||
warnings_found += 1
|
||||
print(f"{YELLOW}[WARNING]{RESET} {msg}")
|
||||
|
||||
def log_success(msg):
|
||||
print(f"{GREEN}[OK]{RESET} {msg}")
|
||||
|
||||
def run_cmd(cmd):
|
||||
return subprocess.check_output(cmd, shell=True, text=True).strip()
|
||||
|
||||
def check_single_commit():
|
||||
print("--- Checking Commit Count ---")
|
||||
try:
|
||||
count = int(run_cmd("git rev-list --count HEAD ^master"))
|
||||
if count > 1:
|
||||
log_error(f"Branch contains {count} commits ahead of master. All changes for a single PR must be squashed into a single commit.")
|
||||
else:
|
||||
log_success("Branch contains a single commit.")
|
||||
except Exception:
|
||||
# Ignore errors if the git command fails (e.g. not a git repo or no master branch)
|
||||
pass
|
||||
|
||||
def check_commit_message():
|
||||
print("--- Checking Commit Message ---")
|
||||
try:
|
||||
msg = run_cmd("git log -1 --pretty=format:%B")
|
||||
lines = msg.split('\n')
|
||||
subject = lines[0]
|
||||
if len(subject) > 50:
|
||||
log_error(f"Commit subject exceeds 50 characters ({len(subject)} chars): '{subject}'")
|
||||
if not subject[0].isupper():
|
||||
log_error(f"Commit subject must be capitalized: '{subject}'")
|
||||
if subject[-1] in ['.', '!', '?']:
|
||||
log_error(f"Commit subject must not end with punctuation: '{subject}'")
|
||||
|
||||
has_body = False
|
||||
for line in lines[1:]:
|
||||
if line.strip() != "":
|
||||
has_body = True
|
||||
break
|
||||
if not has_body:
|
||||
log_error("Commit message must contain a comprehensive body detailing the 'what' and 'why'.")
|
||||
|
||||
if errors_found == 0:
|
||||
log_success("Commit message format looks good.")
|
||||
except Exception as e:
|
||||
log_error(f"Failed to check commit message: {e}")
|
||||
|
||||
def check_workspace_clean():
|
||||
print("\n--- Checking Workspace State ---")
|
||||
status = run_cmd("git status --porcelain")
|
||||
if status:
|
||||
log_error("Workspace is not clean. Uncommitted changes found:\n" + status)
|
||||
else:
|
||||
log_success("Working directory is clean.")
|
||||
|
||||
def check_package_lock():
|
||||
print("\n--- Checking package-lock.json ---")
|
||||
diff_files = run_cmd("git diff HEAD^ --name-only").split('\n')
|
||||
if "console-webapp/package-lock.json" in diff_files:
|
||||
if "console-webapp/package.json" in diff_files or "dependencies.gradle" in diff_files:
|
||||
log_warning("console-webapp/package-lock.json is modified in the diff. This is expected since dependencies were updated.")
|
||||
else:
|
||||
log_error("console-webapp/package-lock.json is modified in the diff. Unless NPM dependencies were explicitly changed, revert this file using: git checkout console-webapp/package-lock.json")
|
||||
else:
|
||||
log_success("console-webapp/package-lock.json is untouched.")
|
||||
|
||||
def check_license_headers():
|
||||
print("\n--- Checking License Headers on New Files ---")
|
||||
current_year = str(datetime.datetime.now().year)
|
||||
added_files = run_cmd("git diff HEAD^ --name-status --diff-filter=A").split('\n')
|
||||
|
||||
java_header = f"// Copyright {current_year} The Nomulus Authors. All Rights Reserved."
|
||||
script_header = f"# Copyright {current_year} The Nomulus Authors. All Rights Reserved."
|
||||
sql_header = f"-- Copyright {current_year} The Nomulus Authors. All Rights Reserved."
|
||||
ftl_header = f"<#-- Copyright {current_year} The Nomulus Authors. All Rights Reserved."
|
||||
|
||||
files_checked = 0
|
||||
|
||||
for f_line in added_files:
|
||||
if not f_line:
|
||||
continue
|
||||
f = f_line.split('\t')[-1]
|
||||
|
||||
expected_header = None
|
||||
if f.endswith('.java') or f.endswith('.js') or f.endswith('.gradle') or f.endswith('.ts'):
|
||||
expected_header = java_header
|
||||
elif f.endswith('.py') or f.endswith('.sh'):
|
||||
expected_header = script_header
|
||||
elif f.endswith('.sql'):
|
||||
expected_header = sql_header
|
||||
elif f.endswith('.ftl'):
|
||||
expected_header = ftl_header
|
||||
|
||||
if expected_header:
|
||||
files_checked += 1
|
||||
try:
|
||||
with open(f, 'r') as file:
|
||||
content = file.read()
|
||||
if expected_header not in content:
|
||||
log_error(f"Missing or incorrect copyright year in {f}. Expected: {expected_header}")
|
||||
except FileNotFoundError:
|
||||
# File might have been deleted or renamed; ignore missing files.
|
||||
pass
|
||||
|
||||
if files_checked == 0:
|
||||
log_success("No new files requiring license headers added.")
|
||||
|
||||
def check_formatting():
|
||||
print("\n--- Checking Project Formatting ---")
|
||||
try:
|
||||
run_cmd("./gradlew spotlessCheck javaIncrementalFormatCheck")
|
||||
log_success("All formatting checks (spotless and javaIncrementalFormat) passed.")
|
||||
except Exception as e:
|
||||
log_error("Formatting checks failed. Run './gradlew spotlessApply javaIncrementalFormatApply' to fix.")
|
||||
|
||||
def check_diff_anti_patterns():
|
||||
print("\n--- Checking Code Anti-Patterns in Diff ---")
|
||||
diff = run_cmd("git diff HEAD^ -U0")
|
||||
current_file = ""
|
||||
|
||||
# Regex Patterns
|
||||
fqn_pattern = re.compile(r'(?<!import\s)(java|google\.registry|com\.google|org)\.[a-z0-9.]+\.[A-Z][a-zA-Z0-9]+')
|
||||
visibility_pattern = re.compile(r'/\*\s*package\s*\*/')
|
||||
utc_pattern = re.compile(r'ZoneId\.of\("UTC"\)')
|
||||
now_pattern = re.compile(r'(Instant\.now\(\)|OffsetDateTime\.now\(\)|System\.currentTimeMillis\(\))')
|
||||
catch_generic_pattern = re.compile(r'catch\s*\(\s*(Exception|Throwable)\s+[a-zA-Z0-9_]+\s*\)')
|
||||
is_equal_optional_pattern = re.compile(r'\.isEqualTo\(Optional\.of\(')
|
||||
sleep_pattern = re.compile(r'Thread\.sleep\(')
|
||||
suppress_pattern = re.compile(r'@SuppressWarnings\(')
|
||||
wrong_nullable_pattern = re.compile(r'import\s+(?!javax\.annotation\.Nullable;)[a-zA-Z0-9_.]+\.Nullable;')
|
||||
utility_class_pattern = re.compile(r'\b(DateTimeUtils|CacheUtils)\.[a-z]')
|
||||
redundant_tx_pattern = re.compile(r'tm\(\)\.transact\(\s*\(\)\s*->\s*tm\(\)\.reTransact')
|
||||
mutable_collection_pattern = re.compile(r'new\s+(ArrayList|HashMap|HashSet)\s*[<()]')
|
||||
trailing_space_pattern = re.compile(r'[ \t]+$')
|
||||
debug_print_pattern = re.compile(r'(System\.(out|err)\.print|\.printStackTrace\(\))')
|
||||
todo_pattern = re.compile(r'\b(TODO|FIXME)\b')
|
||||
unnecessary_cast_pattern = re.compile(r'\(\s*(?:Instant|ImmutableSet|ImmutableList|ImmutableMap)(?:<[^>]+>)?\s*\)')
|
||||
instant_tostring_pattern = re.compile(r'(?i)(?:instant|time|now|clock\.now\(\))\.toString\(\)')
|
||||
dao_transact_pattern = re.compile(r'tm\(\)\.transact\(')
|
||||
retransact_txtime_pattern = re.compile(r'tm\(\)\.reTransact\(\s*(?:\(\)\s*->\s*)?tm\(\)(?:\.|::)get(?:Transaction|Tx)Time\(\)?\s*\)')
|
||||
inject_command_pattern = re.compile(r'inject\(Command\s+[a-zA-Z0-9_]+\)')
|
||||
clock_now_pattern = re.compile(r'clock\.now\(\)')
|
||||
|
||||
suppress_count = 0
|
||||
|
||||
for line in diff.split('\n'):
|
||||
if line.startswith('+++ b/'):
|
||||
current_file = line[6:]
|
||||
suppress_count = 0
|
||||
continue
|
||||
|
||||
if line.startswith('+') and not line.startswith('+++'):
|
||||
code_line = line[1:]
|
||||
|
||||
# Trailing whitespace
|
||||
if trailing_space_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found trailing whitespace.")
|
||||
|
||||
# Skip regex definitions in this script from triggering false positives
|
||||
if 're.compile' not in code_line:
|
||||
# Debug prints
|
||||
if debug_print_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found leftover debug print or stack trace (System. out. println / printStackTrace).")
|
||||
|
||||
# TODOs / FIXMEs
|
||||
if todo_pattern.search(code_line):
|
||||
log_warning(f"[{current_file}] Found new T" "ODO or F" "IXME. Ensure this is intentional before completing the PR.")
|
||||
|
||||
if not current_file.endswith('.java'):
|
||||
continue
|
||||
|
||||
# FQN Check
|
||||
fqn_matches = fqn_pattern.findall(code_line)
|
||||
if fqn_matches:
|
||||
# Skip if the match is exactly part of an import or package declaration
|
||||
if not code_line.strip().startswith('import') and not code_line.strip().startswith('package'):
|
||||
log_warning(f"[{current_file}] Potential Fully-Qualified Name found: {fqn_matches}. Use imports instead.")
|
||||
|
||||
# Package visibility
|
||||
if visibility_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found '/* package */' modifier. Leave modifier blank instead.")
|
||||
|
||||
# Time zones
|
||||
if utc_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found ZoneId.of(\"UTC\"). Use statically imported ZoneOffset.UTC instead.")
|
||||
|
||||
# System clocks
|
||||
if now_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found un-injected clock (Instant.now / System.currentTimeMillis). Inject Clock instead.")
|
||||
|
||||
# Catch generic
|
||||
if catch_generic_pattern.search(code_line):
|
||||
log_warning(f"[{current_file}] Catching generic Exception/Throwable. Use specific exceptions.")
|
||||
|
||||
# Truth Optionals
|
||||
if is_equal_optional_pattern.search(code_line):
|
||||
log_warning(f"[{current_file}] Found .isEqualTo(Optional.of(...)). Use Truth's .hasValue(...) instead.")
|
||||
|
||||
# Thread.sleep
|
||||
if sleep_pattern.search(code_line):
|
||||
log_warning(f"[{current_file}] Found Thread.sleep(). Use Sleeper instead in tests.")
|
||||
|
||||
# SuppressWarnings
|
||||
if suppress_pattern.search(code_line):
|
||||
suppress_count += 1
|
||||
if suppress_count > 1:
|
||||
log_error(f"[{current_file}] Multiple @SuppressWarnings detected. They must be merged (e.g. {{\"unchecked\", \"foo\"}}).")
|
||||
else:
|
||||
suppress_count = 0
|
||||
|
||||
# Wrong Nullable
|
||||
if wrong_nullable_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found incorrect Nullable import. Always use javax.annotation.Nullable.")
|
||||
|
||||
# Missing static imports for utilities
|
||||
if utility_class_pattern.search(code_line):
|
||||
if not code_line.strip().startswith('import'):
|
||||
log_warning(f"[{current_file}] Found un-statically imported method from DateTimeUtils/CacheUtils. Use static imports.")
|
||||
|
||||
# Redundant transaction wrapping
|
||||
if redundant_tx_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found redundant transaction wrapping (tm().transact(() -> tm().reTransact(...))).")
|
||||
|
||||
# Mutable collection instantiation
|
||||
if mutable_collection_pattern.search(code_line):
|
||||
log_warning(f"[{current_file}] Found mutable collection instantiation (ArrayList/HashMap/HashSet). Prefer Guava Immutable collections.")
|
||||
|
||||
# Unnecessary casts
|
||||
if unnecessary_cast_pattern.search(code_line):
|
||||
log_warning(f"[{current_file}] Potential unnecessary cast to Instant or Guava Immutable type. Remove if it compiles without it.")
|
||||
|
||||
# Instant toString
|
||||
if instant_tostring_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found potential Instant.toString(). Use DateTimeUtils.formatInstant(...) to preserve .000Z precision.")
|
||||
|
||||
# DAO transactions
|
||||
if current_file.lower().endswith('dao.java') and dao_transact_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Found tm().transact(...) inside a DAO. Use tm().assertInTransaction() instead.")
|
||||
|
||||
# reTransact around getTxTime in production code
|
||||
if 'src/main/' in current_file and retransact_txtime_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Unnecessary reTransact() around getTxTime() in production code. Wrap the caller in a transaction instead.")
|
||||
|
||||
# inject(Command)
|
||||
if inject_command_pattern.search(code_line):
|
||||
log_error(f"[{current_file}] Generic inject(Command) methods do not work with Dagger. Use explicit concrete types.")
|
||||
|
||||
# clock.now() in tests
|
||||
if 'src/test/' in current_file and clock_now_pattern.search(code_line):
|
||||
log_warning(f"[{current_file}] Prefer using a fixed, static constant Instant over capturing clock.now() in tests to prevent flakiness.")
|
||||
|
||||
def check_missing_tests():
|
||||
print("\n--- Checking for Missing Tests ---")
|
||||
diff_files = run_cmd("git diff HEAD^ --name-only").split('\n')
|
||||
main_files_modified = False
|
||||
test_files_modified = False
|
||||
|
||||
for f in diff_files:
|
||||
if f.startswith('core/src/main/') or f.startswith('util/src/main/'):
|
||||
if f.endswith('.java'):
|
||||
main_files_modified = True
|
||||
if f.startswith('core/src/test/') or f.startswith('util/src/test/'):
|
||||
if f.endswith('Test.java'):
|
||||
test_files_modified = True
|
||||
|
||||
if main_files_modified and not test_files_modified:
|
||||
log_warning("Production code (.java files in src/main/) was modified, but no corresponding tests (.java files in src/test/) were added or updated. You MUST proactively write tests for any new logic or bug fixes.")
|
||||
else:
|
||||
log_success("Test coverage check passed (tests were included or no production Java code was changed).")
|
||||
|
||||
def main():
|
||||
print("========================================")
|
||||
print(" NOMULUS PR POLISHER CHECKLIST ")
|
||||
print("========================================\n")
|
||||
|
||||
check_single_commit()
|
||||
check_commit_message()
|
||||
check_workspace_clean()
|
||||
check_package_lock()
|
||||
check_license_headers()
|
||||
check_missing_tests()
|
||||
check_formatting()
|
||||
check_diff_anti_patterns()
|
||||
|
||||
print("\n========================================")
|
||||
if errors_found == 0 and warnings_found == 0:
|
||||
print(f"{GREEN}SUCCESS: All checks passed. PR is polished!{RESET}")
|
||||
else:
|
||||
print(f"RESULTS: {RED}{errors_found} ERRORS{RESET}, {YELLOW}{warnings_found} WARNINGS{RESET}")
|
||||
print("Please address the above issues before declaring the PR complete.")
|
||||
sys.exit(1 if errors_found > 0 else 0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -46,6 +46,7 @@ This document outlines foundational mandates, architectural patterns, and projec
|
||||
- **Transactional Time:** Ensure code that relies on `tm().getTransactionTime()` (or `tm().getTxTime()`) is executed within a transaction context.
|
||||
|
||||
### 5. Testing Best Practices
|
||||
- **Mandatory Proactive Testing:** You MUST automatically write and update tests alongside your code changes WITHOUT waiting for the user to prompt you. If you add a new feature, fix a bug, or change core logic, you are explicitly required to identify the corresponding `*Test.java` file and implement comprehensive test coverage for your changes.
|
||||
- **FakeClock and Sleeper:** Use `FakeClock` and `Sleeper` for any logic involving timeouts, delays, or expiration.
|
||||
- **Empirical Reproduction:** Before fixing a bug, always create a test case that reproduces the failure.
|
||||
- **Base Classes:** Leverage `CommandTestCase`, `EppToolCommandTestCase`, etc., to reduce boilerplate and ensure consistent setup (e.g., clock initialization).
|
||||
@@ -53,6 +54,13 @@ This document outlines foundational mandates, architectural patterns, and projec
|
||||
|
||||
### 6. Project Dependencies
|
||||
- **Common Module:** When using `Clock` or other core utilities in a new or separate module (like `load-testing`), ensure `implementation project(':common')` is added to the module's `build.gradle`.
|
||||
- **Updating Dependencies:** When updating third-party dependencies, you MUST follow this exact, non-negotiable sequence. NEVER run the update script without first verifying the lockfiles locally.
|
||||
1. Modify `dependencies.gradle`.
|
||||
2. Run `./gradlew dependencies --write-locks --update-locks '*:*'` to regenerate all Gradle lockfiles locally to resolve new versions.
|
||||
3. Run `./gradlew clean build` to exhaustively compile and run all tests against the new transitive dependency tree. If there are compilation or test errors due to breaking API changes or output formatting changes in the new dependency version, your primary goal is to **fix our codebase** to be compliant with the new dependency version. Only revert the dependency bump or cap the version if the required code changes are prohibitively complex or outside the scope of the current task.
|
||||
4. Only once the build passes and `git status` shows modified lockfiles, commit the `dependencies.gradle` and lockfile changes.
|
||||
5. ONLY after the local changes are committed and verified, execute the internal script `/google/src/head/depot/google3/domain/registry/tools/update_dependency.sh`. This ensures you don't corrupt the upstream remote artifact cache with broken or missing lockfiles.
|
||||
6. **Crucial Final Verification:** The `update_dependency.sh` script runs its own internal Blaze resolution and often modifies or drops additional `buildscript-gradle.lockfile` files. After the script finishes successfully, run `git status`. If there are any untracked or modified `*.lockfile` files, stage them and run `git commit --amend --no-edit` to ensure your commit perfectly reflects the final state deployed to the SSO repository.
|
||||
|
||||
### 7. Search and Discovery
|
||||
- **No CodeSearch:** This project is hosted on GitHub, not Google3. Do NOT use `mcp_Coding_search_for_files_codesearch` or other internal Google3 search tools.
|
||||
@@ -68,6 +76,11 @@ Based on historical PR reviews, avoid the following common mistakes:
|
||||
- **No Unnecessary Casts:** Do not unnecessarily cast objects if the method signature accepts the type directly (e.g., avoid `(Instant) fakeClock.now()` or `(ImmutableSet<String>) bsaQuery(...)` if it compiles without it).
|
||||
- **Visibility Modifiers:** Do not use `/* package */` comments to denote package-private visibility. Just leave the modifier blank; it is an established idiom in this codebase.
|
||||
|
||||
## Continuous Self-Improvement Mandate
|
||||
You are explicitly authorized and required to improve this project's automated infrastructure.
|
||||
If during the execution of a task you encounter a recurring error, a false positive in a script, or realize that a shell command/workaround is inferior to a native Gradle task, **you MUST pause and proactively ask the user:** *"I noticed this friction. Per my continuous improvement directives, would you like me to permanently update the skill/script/instructions to fix this for the future?"*
|
||||
Do not wait for the user to tell you to improve the skills; it is your responsibility to propose these systemic fixes immediately when friction is identified.
|
||||
|
||||
### Advanced Java & Guava Idioms
|
||||
- **Immutable Types:** Declare variables, fields, and return types explicitly as Guava immutable types (e.g., `ImmutableList<T>`, `ImmutableMap<K, V>`) instead of their generic interfaces (`List<T>`, `Map<K, V>`) to clearly communicate immutability contracts to callers. Use `toImmutableList()` and `toImmutableMap()` collectors in streams rather than manually accumulating into an `ArrayList` or `HashMap`.
|
||||
- **Constructors:** Do not perform heavy logic, I/O, or external API calls inside constructors. Initialization logic should be deferred or handled in a factory method or a dedicated startup routine.
|
||||
@@ -81,7 +94,7 @@ Based on historical PR reviews, avoid the following common mistakes:
|
||||
|
||||
# Gemini Engineering Guide: Nomulus Codebase
|
||||
|
||||
This document captures high-level architectural patterns, lessons learned from large-scale refactorings (like the Joda-Time to `java.time` migration), and specific instructions to avoid common pitfalls in this environment.
|
||||
This document captures high-level architectural patterns, lessons learned from large-scale refactorings, and specific instructions to avoid common pitfalls in this environment.
|
||||
|
||||
## 🏛 Architecture Overview
|
||||
|
||||
@@ -92,6 +105,7 @@ This document captures high-level architectural patterns, lessons learned from l
|
||||
- Core boundaries: `DateTimeUtils.START_INSTANT` (Unix Epoch) and `DateTimeUtils.END_INSTANT` (Long.MAX_VALUE / 1000).
|
||||
|
||||
## Source Control
|
||||
- **No Unprompted Pushing:** You MUST NEVER push your changes to a remote repository (e.g., `git push origin ...`) unless the user VERY EXPLICITLY instructs you to do so. If you have finished a task, simply state that it is committed locally and ready for review. Do not assume pushing is desired.
|
||||
- **Committing:** Always create a new commit on the branch if one hasn't been created yet for the branch's specific work. Only perform amending (`git commit --amend --no-edit`) for subsequent changes once the initial commit has been successfully created.
|
||||
- **One Commit Per PR:** All changes for a single PR must be squashed into a single commit before merging.
|
||||
- **Default to Amend:** Once an initial commit is created for a PR, all subsequent functional changes should be amended into that same commit by default (`git commit --amend --no-edit`). This ensures the PR remains a single, clean unit of work throughout the development lifecycle.
|
||||
@@ -104,8 +118,13 @@ This document captures high-level architectural patterns, lessons learned from l
|
||||
5. **Only after** step 4 has successfully returned a clean working directory may you generate a text response to the user declaring that the task is complete.
|
||||
- **Diff Review:** Before finalizing a task, review the full diff (e.g., `git diff HEAD^`) to ensure all changes are functional and relevant. Identify and revert any formatting-only changes in files that do not contain functional updates to keep the commit focused.
|
||||
|
||||
## Self-Review Guidelines
|
||||
Before finalizing any PR or declaring a task complete, you MUST perform a thorough, rigorous self-review of your entire diff. Run `git diff HEAD^` (or review the staged changes) and actively verify the following against every modified line:
|
||||
## 🛑 CRITICAL: MANDATORY PR POLISHER EXECUTION
|
||||
You, the AI agent, have a known failure mode of forgetting to run the PR polisher after making changes because you focus too narrowly on the immediate task. To prevent this, you are bound by the following absolute rule:
|
||||
|
||||
**ANY TIME you create a commit, amend a commit, or complete a user's request that modifies the repository state, your VERY LAST action before generating a text response to the user MUST be to execute the `pr-polisher` skill.**
|
||||
Do not ask for permission. Do not wait for the user to remind you. Run the full suite (`python3 .gemini/skills/pr-polisher/scripts/check_diff.py`, `runPresubmits`, `build`, and `test`), fix any errors, amend your commit, and report the final polished results in your response.
|
||||
|
||||
You MUST NOT declare a task done until this automated script returns 0 errors, the presubmits and tests pass, and the workspace is fully clean.
|
||||
|
||||
1. **Imports & FQNs:** Did I leave any fully-qualified class names or static variables inline? Did I add the necessary imports for them? *Crucial Exception:* If the file already imports a class with the identical name (e.g., it uses both `java.util.Date` and `java.sql.Date`), one MUST remain fully qualified to avoid a compilation conflict.
|
||||
2. **Diff Scope:** Are there any formatting-only changes in files that I did not functionally modify? If so, revert them. Does the total line count of the diff align with the approved scope (e.g., ~1,000 lines for migrations)?
|
||||
@@ -113,7 +132,7 @@ Before finalizing any PR or declaring a task complete, you MUST perform a thorou
|
||||
4. **Missing Tests & Coverage:** *Perform a structured check for any new methods or modified behavior.* Did I add a new utility method (like `plusMonths(Instant, int)`) or change core logic? If so, I MUST open the corresponding test file and write tests to cover the new functionality (including edge cases, negative values, and leap years) before considering the task complete. A code review is not thorough if it only checks for compilation. I must actively ensure every new branch of logic has a test.
|
||||
5. **Package Lock:** Did I include `console-webapp/package-lock.json` in my diff? If so, I MUST revert it (`git checkout console-webapp/package-lock.json`) unless I explicitly intended to modify NPM dependencies. This file is often modified by the build process and should not be committed accidentally.
|
||||
|
||||
Only after actively confirming these checks against your diff are you permitted to finalize the task.
|
||||
Only after actively executing the `pr-polisher` skill and confirming these checks against your diff are you permitted to finalize the task.
|
||||
|
||||
## Refactoring & Migration Guardrails
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Nomulus is an open source, scalable, cloud-based service for operating
|
||||
[top-level domains](https://en.wikipedia.org/wiki/Top-level_domain) (TLDs). It
|
||||
is the authoritative source for the TLDs that it runs, meaning that it is
|
||||
responsible for tracking domain name ownership and handling registrations,
|
||||
renewals, availability checks, and WHOIS requests. End-user registrants (i.e.,
|
||||
renewals, availability checks, and RDAP requests. End-user registrants (i.e.,
|
||||
people or companies that want to register a domain name) use an intermediate
|
||||
domain name registrar acting on their behalf to interact with the registry.
|
||||
|
||||
@@ -97,7 +97,7 @@ Nomulus has the following capabilities:
|
||||
for details), and an implementation based on
|
||||
[Google Cloud Secret Manager](https://cloud.google.com/security/products/secret-manager) is
|
||||
available.
|
||||
* **TPC Proxy**: Nomulus is built on top of the [Jetty](https://jetty.org/)
|
||||
* **TCP Proxy**: Nomulus is built on top of the [Jetty](https://jetty.org/)
|
||||
container that implements the [Jakarta Servlet](https://jakarta.ee/specifications/servlet/)
|
||||
specification and only serves HTTP/S traffic. A proxy to translate raw TCP traffic (e.g., EPP)
|
||||
to and from HTTP is provided.
|
||||
|
||||
@@ -609,3 +609,23 @@ gradle.taskGraph.whenReady { graph ->
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task fastBuild {
|
||||
group = 'build'
|
||||
description = 'A lightweight build for local dev. Compiles Java, runs standard tests, and checks formatting, but skips Docker images, fragile tests, and the massive Angular console builds. (Do not use this target to verify console changes.)'
|
||||
|
||||
dependsOn build
|
||||
// Remove the heavy default dependencies specifically for fastBuild
|
||||
gradle.taskGraph.whenReady { graph ->
|
||||
if (graph.hasTask(fastBuild)) {
|
||||
project(':console-webapp').tasks.named('buildConsoleForAll').get().enabled = false
|
||||
project(':jetty').tasks.named('buildNomulusImage').get().enabled = false
|
||||
project(':core').tasks.named('buildToolImage').get().enabled = false
|
||||
project(':core').tasks.named('fragileTest').get().enabled = false
|
||||
project(':jetty').tasks.named('stage').get().enabled = false
|
||||
if (project.tasks.findByName('stage') != null) {
|
||||
project.tasks.named('stage').get().enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,12 +68,12 @@ org.jacoco:org.jacoco.core:0.8.14=jacocoAnt
|
||||
org.jacoco:org.jacoco.report:0.8.14=jacocoAnt
|
||||
org.javassist:javassist:3.28.0-GA=checkstyle
|
||||
org.jspecify:jspecify:1.0.0=annotationProcessor,checkstyle,compileClasspath,deploy_jar,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath,testing,testingAnnotationProcessor,testingCompileClasspath
|
||||
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-engine:5.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-commons:1.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-engine:1.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-launcher:1.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit:junit-bom:5.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-api:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-engine:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-commons:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-engine:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-launcher:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit:junit-bom:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.9=jacocoAnt
|
||||
org.ow2.asm:asm-tree:9.9=jacocoAnt
|
||||
|
||||
@@ -9,15 +9,14 @@ expected to change.
|
||||
|
||||
## Deployment
|
||||
|
||||
The webapp is deployed with the nomulus default service war to GKE.
|
||||
During nomulus default service war build task, gradle script triggers the
|
||||
following:
|
||||
The webapp is deployed as part of the default Nomulus GKE service image.
|
||||
During the image build task, the Gradle script triggers the following:
|
||||
|
||||
1) Console webapp build script `buildConsoleWebapp`, which installs
|
||||
dependencies, assembles a compiled ts -> js, minified, optimized static
|
||||
artifact (html, css, js)
|
||||
2) Artifact assembled in step 1 then gets copied to core project web artifact
|
||||
location, so that it can be deployed with the rest of the core webapp
|
||||
2) Artifact assembled in step 1 then gets copied to the jetty webapp resource
|
||||
location, so that it can be staged inside the default GKE service container.
|
||||
|
||||
## Development server
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@ task runConsoleWebappUnitTests(type: Exec) {
|
||||
|
||||
task buildConsoleWebapp(type: Exec) {
|
||||
workingDir "${consoleDir}/"
|
||||
executable 'npm'
|
||||
executable 'npx'
|
||||
def configuration = project.getProperty('configuration')
|
||||
args 'run', "build", "--configuration=${configuration}"
|
||||
args 'ng', 'build', '--base-href=/console/', "--configuration=${configuration}", "--output-path=staged/dist"
|
||||
doFirst {
|
||||
println "Building console for environment: ${configuration}"
|
||||
}
|
||||
@@ -52,8 +52,8 @@ task buildConsoleForAll() {}
|
||||
def createConsoleTask = { env ->
|
||||
project.tasks.register("buildConsoleFor${env.capitalize()}", Exec) {
|
||||
workingDir "${consoleDir}/"
|
||||
executable 'npm'
|
||||
args 'run', 'build', "--configuration=${env}"
|
||||
executable 'npx'
|
||||
args 'ng', 'build', '--base-href=/console/', "--configuration=${env}"
|
||||
doFirst {
|
||||
println "Building console for environment: ${env}"
|
||||
}
|
||||
@@ -107,3 +107,4 @@ tasks.applyFormatting.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.checkFormatting.dependsOn(tasks.npmInstallDeps)
|
||||
tasks.build.dependsOn(tasks.checkFormatting)
|
||||
tasks.build.dependsOn(tasks.runConsoleWebappUnitTests)
|
||||
tasks.build.dependsOn(tasks.buildConsoleForAll)
|
||||
|
||||
Generated
+7
-7
@@ -629,15 +629,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/build/node_modules/@types/node": {
|
||||
"version": "25.7.0",
|
||||
"resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@types/node/-/node-25.7.0.tgz",
|
||||
"integrity": "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg==",
|
||||
"version": "25.9.1",
|
||||
"resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/@types/node/-/node-25.9.1.tgz",
|
||||
"integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.21.0"
|
||||
"undici-types": ">=7.24.0 <7.24.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/build/node_modules/@vitejs/plugin-basic-ssl": {
|
||||
@@ -744,9 +744,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/build/node_modules/undici-types": {
|
||||
"version": "7.21.0",
|
||||
"resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/undici-types/-/undici-types-7.21.0.tgz",
|
||||
"integrity": "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ==",
|
||||
"version": "7.24.6",
|
||||
"resolved": "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/undici-types/-/undici-types-7.24.6.tgz",
|
||||
"integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
|
||||
@@ -48,7 +48,11 @@ interface DomainData {
|
||||
selector: 'app-response-dialog',
|
||||
template: `
|
||||
<h2 mat-dialog-title>{{ data.title }}</h2>
|
||||
<mat-dialog-content [innerHTML]="data.content" />
|
||||
<mat-dialog-content>
|
||||
@for (line of data.content; track line) {
|
||||
<div>{{ line }}</div>
|
||||
}
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions>
|
||||
<button mat-button (click)="onClose()">Close</button>
|
||||
</mat-dialog-actions>
|
||||
@@ -59,7 +63,7 @@ export class ResponseDialogComponent {
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<ReasonDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
public data: { title: string; content: string }
|
||||
public data: { title: string; content: string[] }
|
||||
) {}
|
||||
|
||||
onClose(): void {
|
||||
@@ -312,11 +316,13 @@ export class DomainListComponent {
|
||||
this.dialog.open(ResponseDialogComponent, {
|
||||
data: {
|
||||
title: 'Domain Deletion Results',
|
||||
content: `Successfully deleted - ${successCount} domain(s)<br/>Failed to delete - ${failureCount} domain(s)<br/>${
|
||||
content: [
|
||||
`Successfully deleted - ${successCount} domain(s)`,
|
||||
`Failed to delete - ${failureCount} domain(s)`,
|
||||
failureCount
|
||||
? 'Some domains could not be deleted due to ongoing processes or server errors. '
|
||||
: ''
|
||||
}Please check the table for more information.`,
|
||||
? 'Some domains could not be deleted due to ongoing processes or server errors. Please check the table for more information.'
|
||||
: 'Please check the table for more information.',
|
||||
],
|
||||
},
|
||||
});
|
||||
this.selection.clear();
|
||||
|
||||
@@ -97,10 +97,9 @@
|
||||
@for (column of columns; track column.columnDef) {
|
||||
<mat-list-item role="listitem">
|
||||
<span class="console-app__list-key">{{ column.header }} </span>
|
||||
<span
|
||||
class="console-app__list-value"
|
||||
[innerHTML]="column.cell(registrarInEdit).replace('<br/>', ' ')"
|
||||
></span>
|
||||
<span class="console-app__list-value">{{
|
||||
column.cell(registrarInEdit)
|
||||
}}</span>
|
||||
</mat-list-item>
|
||||
<mat-divider></mat-divider>
|
||||
}
|
||||
|
||||
@@ -49,10 +49,9 @@
|
||||
<mat-header-cell *matHeaderCellDef>
|
||||
{{ column.header }}
|
||||
</mat-header-cell>
|
||||
<mat-cell
|
||||
*matCellDef="let row"
|
||||
[innerHTML]="column.cell(row)"
|
||||
></mat-cell>
|
||||
<mat-cell *matCellDef="let row" style="white-space: pre-wrap">{{
|
||||
column.cell(row)
|
||||
}}</mat-cell>
|
||||
</ng-container>
|
||||
}
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
|
||||
@@ -56,7 +56,7 @@ export const columns = [
|
||||
cell: (record: Registrar) =>
|
||||
`${Object.entries(record.billingAccountMap || {}).reduce(
|
||||
(acc, [key, val]) => {
|
||||
return `${acc}${key}=${val}<br/>`;
|
||||
return `${acc}${key}=${val}\n`;
|
||||
},
|
||||
''
|
||||
)}`,
|
||||
|
||||
@@ -25,7 +25,18 @@
|
||||
@for (column of columns; track column) {
|
||||
<ng-container [matColumnDef]="column.columnDef">
|
||||
<mat-header-cell *matHeaderCellDef> {{ column.header }} </mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" [innerHTML]="column.cell(row)"></mat-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
@if (column.columnDef === 'name') {
|
||||
<div class="contact__name-column">
|
||||
<div class="contact__name-column-title">{{ row.name }}</div>
|
||||
<div class="contact__name-column-roles">
|
||||
{{ row.userFriendlyTypes.join(" • ") }}
|
||||
</div>
|
||||
</div>
|
||||
} @else {
|
||||
{{ column.cell(row) }}
|
||||
}
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
}
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
|
||||
@@ -34,14 +34,7 @@ export default class ContactComponent {
|
||||
{
|
||||
columnDef: 'name',
|
||||
header: 'Name',
|
||||
cell: (contact: ViewReadyContact) => `
|
||||
<div class="contact__name-column">
|
||||
<div class="contact__name-column-title">${contact.name}</div>
|
||||
<div class="contact__name-column-roles">${contact.userFriendlyTypes.join(
|
||||
' • '
|
||||
)}</div>
|
||||
</div>
|
||||
`,
|
||||
cell: (contact: ViewReadyContact) => `${contact.name}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'emailAddress',
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<mat-header-cell *matHeaderCellDef>
|
||||
{{ column.header }}
|
||||
</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row" [innerHTML]="column.cell(row)"></mat-cell>
|
||||
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
|
||||
</ng-container>
|
||||
}
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
|
||||
+8
-26
@@ -53,14 +53,7 @@ def dockerIncompatibleTestPatterns = [
|
||||
// affected by global states outside of Nomulus classes, e.g., threads and
|
||||
// objects retained by frameworks.
|
||||
// TODO(weiminyu): identify cause and fix offending tests.
|
||||
def fragileTestPatterns = [
|
||||
// Breaks random other tests when running with standardTests.
|
||||
"google/registry/bsa/UploadBsaUnavailableDomainsActionTest.*",
|
||||
// Currently changes a global configuration parameter that for some reason
|
||||
// results in timestamp inversions for other tests. TODO(mmuller): fix.
|
||||
"google/registry/flows/host/HostInfoFlowTest.*",
|
||||
"google/registry/beam/common/RegistryPipelineWorkerInitializerTest.*",
|
||||
] + dockerIncompatibleTestPatterns
|
||||
def fragileTestPatterns = dockerIncompatibleTestPatterns
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
@@ -165,10 +158,6 @@ dependencies {
|
||||
implementation deps['com.google.flogger:flogger']
|
||||
implementation deps['com.google.guava:guava']
|
||||
implementation deps['com.google.protobuf:protobuf-java']
|
||||
// Might need to add this back if we re-add nebula-lint
|
||||
// gradleLint.ignore('unused-dependency') {
|
||||
implementation deps['com.google.gwt:gwt-user']
|
||||
// }
|
||||
implementation deps['com.google.cloud:google-cloud-compute']
|
||||
implementation deps['com.google.cloud:google-cloud-core']
|
||||
implementation deps['com.google.cloud:google-cloud-storage']
|
||||
@@ -181,8 +170,7 @@ dependencies {
|
||||
implementation deps['com.google.oauth-client:google-oauth-client-servlet']
|
||||
implementation deps['com.google.re2j:re2j']
|
||||
implementation deps['org.freemarker:freemarker']
|
||||
implementation deps['com.googlecode.json-simple:json-simple']
|
||||
implementation deps['com.jcraft:jsch']
|
||||
implementation deps['com.github.mwiede:jsch']
|
||||
implementation deps['com.zaxxer:HikariCP']
|
||||
implementation deps['com.squareup.okhttp3:okhttp']
|
||||
implementation deps['dnsjava:dnsjava']
|
||||
@@ -285,6 +273,7 @@ dependencies {
|
||||
testImplementation deps['org.junit-pioneer:junit-pioneer']
|
||||
testImplementation deps['org.junit.platform:junit-platform-runner']
|
||||
testImplementation deps['org.junit.platform:junit-platform-suite-api']
|
||||
testImplementation deps['org.junit.platform:junit-platform-suite']
|
||||
testImplementation deps['org.mockito:mockito-core']
|
||||
testImplementation deps['org.mockito:mockito-junit-jupiter']
|
||||
|
||||
@@ -453,7 +442,7 @@ project.tasks.create('generateSqlSchema', JavaExec) {
|
||||
mainClass = 'google.registry.tools.DevTool'
|
||||
jvmArgs "--sun-misc-unsafe-memory-access=allow"
|
||||
args = [
|
||||
'-e', 'alpha',
|
||||
'-e', 'unittest',
|
||||
'generate_sql_schema', '--start_postgresql', '-o',
|
||||
"${rootProject.projectRootDir}/db/src/main/resources/sql/schema/" +
|
||||
"db-schema.sql.generated"
|
||||
@@ -705,10 +694,7 @@ task fragileTest(type: FilteringTest) {
|
||||
|
||||
// Dedicated test suite for schema-dependent tests.
|
||||
task sqlIntegrationTest(type: FilteringTest) {
|
||||
// TestSuite still requires a JUnit 4 runner, which knows how to handle JUnit 5 tests.
|
||||
// Here we need to override parent's choice of JUnit 5. If changing this, remember to
|
||||
// change :integration:sqlIntegrationTest too.
|
||||
useJUnit()
|
||||
useJUnitPlatform()
|
||||
excludeTestCases = false
|
||||
tests = ['google/registry/schema/integration/SqlIntegrationTestSuite.*']
|
||||
|
||||
@@ -755,13 +741,9 @@ test {
|
||||
// Don't run any tests from this task, all testing gets done in the
|
||||
// FilteringTest tasks.
|
||||
exclude "**"
|
||||
// TODO(weiminyu): Remove dependency on sqlIntegrationTest
|
||||
}.dependsOn(fragileTest, standardTest, registryToolIntegrationTest, sqlIntegrationTest)
|
||||
}.dependsOn(standardTest, registryToolIntegrationTest, sqlIntegrationTest, fragileTest)
|
||||
|
||||
// When we override tests, we also break the cleanTest command.
|
||||
cleanTest.dependsOn(cleanFragileTest, cleanStandardTest,
|
||||
cleanRegistryToolIntegrationTest, cleanSqlIntegrationTest)
|
||||
cleanTest.dependsOn(cleanStandardTest, cleanRegistryToolIntegrationTest, cleanSqlIntegrationTest, cleanFragileTest)
|
||||
|
||||
project.build.dependsOn devtool
|
||||
project.build.dependsOn buildToolImage
|
||||
project.build.dependsOn ':stage'
|
||||
project.build.dependsOn devtool, buildToolImage
|
||||
|
||||
+173
-184
@@ -4,14 +4,14 @@
|
||||
args4j:args4j:2.33=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.charleskorn.kaml:kaml:0.20.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-annotations:2.21=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-core:2.20.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-databind:2.20.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.20.2=testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.20.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-joda:2.20.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.20.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson:jackson-bom:2.20.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.woodstox:woodstox-core:7.0.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-core:2.21.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.core:jackson-databind:2.21.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.21.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.21.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-joda:2.21.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.21.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.jackson:jackson-bom:2.21.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.fasterxml.woodstox:woodstox-core:7.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.ben-manes.caffeine:caffeine:3.0.5=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.github.ben-manes.caffeine:caffeine:3.2.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.docker-java:docker-java-api:3.4.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -26,6 +26,7 @@ com.github.jnr:jnr-posix:3.1.22=compileClasspath,deploy_jar,nonprodCompileClassp
|
||||
com.github.jnr:jnr-unixsocket:0.38.25=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-x86asm:1.0.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.github.mwiede:jsch:2.28.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.android:annotations:4.1.1.4=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api-client:google-api-client-jackson2:2.0.1=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.api-client:google-api-client-jackson2:2.7.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
@@ -33,60 +34,64 @@ com.google.api-client:google-api-client-java6:2.1.4=compileClasspath,deploy_jar,
|
||||
com.google.api-client:google-api-client-servlet:2.7.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api-client:google-api-client-servlet:2.9.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.api-client:google-api-client:2.9.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:gapic-google-cloud-storage-v2:2.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.api.grpc:gapic-google-cloud-storage-v2:2.68.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1:3.21.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.193.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta2:0.193.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:gapic-google-cloud-storage-v2:2.64.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:gapic-google-cloud-storage-v2:2.68.0=testCompileClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1:3.24.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.196.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta2:0.196.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-bigtable-v2:2.73.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.130.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:6.111.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:6.111.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-spanner-v1:6.111.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.132.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:6.113.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:6.113.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-spanner-v1:6.113.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-storage-control-v2:2.44.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-storage-v2:2.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-storage-v2:2.68.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-common-protos:2.65.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1:3.21.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1alpha:3.21.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta1:0.193.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta2:0.193.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta:3.21.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-storage-v2:2.64.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:grpc-google-cloud-storage-v2:2.68.0=testCompileClasspath
|
||||
com.google.api.grpc:grpc-google-common-protos:2.67.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1:3.24.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1alpha:3.24.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta1:0.196.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta2:0.196.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta:3.24.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigtable-admin-v2:2.73.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigtable-v2:2.73.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-compute-v1:1.82.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-datastore-v1:0.125.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-firestore-v1:3.37.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-bigtable-v2:2.75.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-compute-v1:1.102.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-datastore-v1:0.128.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-firestore-v1:3.39.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-logging-v2:0.118.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-monitoring-v3:3.85.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-pubsub-v1:1.130.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-secretmanager-v1:2.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-secretmanager-v1beta2:2.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:6.111.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:6.111.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-spanner-v1:6.111.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-pubsub-v1:1.132.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-secretmanager-v1:2.51.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-secretmanager-v1:2.92.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.api.grpc:proto-google-cloud-secretmanager-v1beta1:2.92.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.api.grpc:proto-google-cloud-secretmanager-v1beta2:2.51.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-secretmanager-v1beta2:2.92.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:6.113.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:6.113.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-spanner-v1:6.113.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-storage-control-v2:2.44.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-storage-v2:2.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-storage-v2:2.64.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-storage-v2:2.68.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-tasks-v2:2.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-tasks-v2beta2:0.141.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-tasks-v2beta3:0.141.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-common-protos:2.60.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-iam-v1:1.60.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.api.grpc:proto-google-iam-v1:1.66.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:api-common:2.57.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.api:api-common:2.63.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax-grpc:2.74.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.api:gax-grpc:2.80.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax-httpjson:2.74.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.api:gax-httpjson:2.80.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax:2.74.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-admin-directory:directory_v1-rev20260421-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-tasks-v2:2.51.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-tasks-v2:2.92.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.api.grpc:proto-google-cloud-tasks-v2beta2:0.141.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-tasks-v2beta2:0.182.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.api.grpc:proto-google-cloud-tasks-v2beta3:0.141.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-cloud-tasks-v2beta3:0.182.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.api.grpc:proto-google-common-protos:2.71.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api.grpc:proto-google-iam-v1:1.62.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.api.grpc:proto-google-iam-v1:1.66.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:api-common:2.63.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax-grpc:2.80.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax-httpjson:2.80.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.api:gax:2.80.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-admin-directory:directory_v1-rev20260522-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-bigquery:v2-rev20251012-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20250606-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dataflow:v1b3-rev20260503-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dns:v1-rev20260421-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-drive:v3-rev20260428-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-gmail:v1-rev20260511-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-gmail:v1-rev20260525-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-groupssettings:v1-rev20220614-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-healthcare:v1-rev20240130-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-iam:v2-rev20250502-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -94,13 +99,10 @@ com.google.apis:google-api-services-iamcredentials:v1-rev20211203-2.0.0=compileC
|
||||
com.google.apis:google-api-services-monitoring:v3-rev20260129-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20220904-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sheets:v4-rev20260213-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev20260317-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-storage:v1-rev20251118-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.apis:google-api-services-storage:v1-rev20260204-2.0.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.46.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.47.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-oauth2-http:1.46.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.auth:google-auth-library-oauth2-http:1.47.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev20260510-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-storage:v1-rev20260204-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.47.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-oauth2-http:1.47.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auto.service:auto-service-annotations:1.0.1=nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.auto.service:auto-service-annotations:1.1.1=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auto.service:auto-service:1.1.1=annotationProcessor
|
||||
@@ -111,34 +113,40 @@ com.google.auto:auto-common:1.2.2=annotationProcessor,nonprodAnnotationProcessor
|
||||
com.google.cloud.bigdataoss:gcsio:2.2.26=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.bigdataoss:util:2.2.26=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.bigtable:bigtable-client-core-config:1.28.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:2.34.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:2.37.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.opentelemetry:detector-resources-support:0.33.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.opentelemetry:exporter-metrics:0.33.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.opentelemetry:shared-resourcemapping:0.33.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.28.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:postgres-socket-factory:1.28.3=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-bigquerystorage:3.21.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.28.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:postgres-socket-factory:1.28.4=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-bigquerystorage:3.24.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-bigtable:2.73.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-compute:1.82.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-core-grpc:2.64.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.cloud:google-cloud-compute:1.102.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-core-grpc:2.66.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.cloud:google-cloud-core-grpc:2.70.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-core-http:2.54.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.cloud:google-cloud-core-http:2.70.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-core:2.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-firestore:3.37.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-core-http:2.66.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-core-http:2.70.0=testCompileClasspath
|
||||
com.google.cloud:google-cloud-core:2.66.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.cloud:google-cloud-core:2.70.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-firestore:3.39.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-logging:3.29.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-monitoring:3.85.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-nio:0.132.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-pubsub:1.148.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-secretmanager:2.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-spanner:6.111.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-nio:0.127.24=testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-nio:0.132.0=testCompileClasspath
|
||||
com.google.cloud:google-cloud-pubsub:1.150.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-secretmanager:2.51.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-secretmanager:2.92.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.cloud:google-cloud-spanner:6.113.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-storage-control:2.44.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-storage:2.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-tasks:2.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-storage:2.64.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-storage:2.68.0=testCompileClasspath
|
||||
com.google.cloud:google-cloud-tasks:2.51.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-tasks:2.92.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.cloud:grpc-gcp:1.9.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:libraries-bom:26.48.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:proto-google-cloud-firestore-bundle-v1:3.37.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:proto-google-cloud-firestore-bundle-v1:3.39.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.code.gson:gson:2.13.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.code.gson:gson:2.14.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.dagger:dagger-compiler:2.59.2=annotationProcessor,testAnnotationProcessor
|
||||
com.google.dagger:dagger-spi:2.59.2=annotationProcessor,testAnnotationProcessor
|
||||
com.google.dagger:dagger:2.59.2=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -161,19 +169,14 @@ com.google.guava:guava:33.4.8-jre=checkstyle
|
||||
com.google.guava:guava:33.5.0-jre=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.guava:guava:33.6.0-jre=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.gwt:gwt-user:2.10.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-apache-v2:2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.http-client:google-http-client-apache-v2:2.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-appengine:1.46.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.http-client:google-http-client-appengine:2.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-apache-v2:2.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-appengine:2.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-gson:2.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-jackson2:1.46.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.http-client:google-http-client-jackson2:2.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-jackson2:2.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-protobuf:2.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client:2.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.j2objc:j2objc-annotations:3.0.0=checkstyle
|
||||
com.google.j2objc:j2objc-annotations:3.1=annotationProcessor,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.jsinterop:jsinterop-annotations:2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.monitoring-client:contrib:1.0.7=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.monitoring-client:metrics:1.0.7=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.monitoring-client:stackdriver:1.0.7=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -184,23 +187,21 @@ com.google.oauth-client:google-oauth-client-jetty:1.39.0=compileClasspath,nonpro
|
||||
com.google.oauth-client:google-oauth-client-servlet:1.36.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.oauth-client:google-oauth-client-servlet:1.39.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
com.google.oauth-client:google-oauth-client:1.39.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java-util:4.33.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.protobuf:protobuf-java-util:4.35.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java-util:4.33.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.protobuf:protobuf-java:4.33.2=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.protobuf:protobuf-java:4.35.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.re2j:re2j:1.8=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.truth:truth:1.4.5=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.googlecode.json-simple:json-simple:1.1.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.ibm.icu:icu4j:73.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.jcraft:jsch:0.1.55=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.lmax:disruptor:3.4.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.puppycrawl.tools:checkstyle:10.24.0=checkstyle
|
||||
com.squareup.okhttp3:okhttp:4.12.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.squareup.okhttp3:okhttp-jvm:5.3.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.squareup.okhttp3:okhttp:5.3.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.squareup.okio:okio-bom:3.0.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.squareup.okio:okio-fakefilesystem-jvm:3.4.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.squareup.okio:okio-fakefilesystem:3.4.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.squareup.okio:okio-jvm:3.6.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.squareup.okio:okio:3.6.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.squareup.okio:okio-jvm:3.16.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.squareup.okio:okio:3.16.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.squareup.wire:wire-compiler:4.5.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.squareup.wire:wire-grpc-server-generator:4.5.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.squareup.wire:wire-grpc-server:4.5.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
@@ -217,8 +218,8 @@ com.squareup:kotlinpoet:1.11.0=annotationProcessor,testAnnotationProcessor
|
||||
com.squareup:kotlinpoet:1.15.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.sun.istack:istack-commons-runtime:4.1.2=deploy_jar,jaxb,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
com.sun.istack:istack-commons-tools:4.1.2=jaxb
|
||||
com.sun.xml.bind.external:relaxng-datatype:4.0.8=jaxb
|
||||
com.sun.xml.bind.external:rngom:4.0.8=jaxb
|
||||
com.sun.xml.bind.external:relaxng-datatype:4.0.9=jaxb
|
||||
com.sun.xml.bind.external:rngom:4.0.9=jaxb
|
||||
com.sun.xml.dtd-parser:dtd-parser:1.5.1=jaxb
|
||||
com.zaxxer:HikariCP:7.0.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
commons-beanutils:commons-beanutils:1.10.1=checkstyle
|
||||
@@ -227,7 +228,7 @@ commons-codec:commons-codec:1.19.0=compileClasspath,deploy_jar,nonprodCompileCla
|
||||
commons-collections:commons-collections:3.2.2=checkstyle
|
||||
commons-io:commons-io:2.20.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
commons-logging:commons-logging:1.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
dnsjava:dnsjava:3.6.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
dnsjava:dnsjava:3.6.5=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
guru.nidi.com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0=testRuntimeClasspath
|
||||
guru.nidi.com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0=testRuntimeClasspath
|
||||
guru.nidi.com.eclipsesource.j2v8:j2v8_win32_x86:4.6.0=testRuntimeClasspath
|
||||
@@ -242,42 +243,31 @@ io.github.eisop:dataflow-errorprone:3.41.0-eisop1=annotationProcessor,nonprodAnn
|
||||
io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.17=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.github.ss-bhatt:testcontainers-valkey:1.0.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-alts:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-alts:1.81.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-api:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-api:1.81.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-auth:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-auth:1.81.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-census:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-context:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-context:1.81.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-core:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-core:1.81.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-googleapis:1.76.2=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-googleapis:1.81.0=testRuntimeClasspath
|
||||
io.grpc:grpc-grpclb:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-alts:1.81.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-api:1.81.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-auth:1.81.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-census:1.76.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-context:1.81.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-core:1.81.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-googleapis:1.81.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-grpclb:1.76.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-grpclb:1.81.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-inprocess:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-inprocess:1.81.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-netty-shaded:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-netty-shaded:1.81.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-netty:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-opentelemetry:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-inprocess:1.81.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-netty-shaded:1.81.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-netty:1.76.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-opentelemetry:1.76.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-opentelemetry:1.81.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-protobuf-lite:1.76.2=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-protobuf-lite:1.81.0=testRuntimeClasspath
|
||||
io.grpc:grpc-protobuf:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-protobuf:1.81.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-rls:1.76.2=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-protobuf-lite:1.81.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-protobuf:1.81.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-rls:1.76.3=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-rls:1.81.0=testRuntimeClasspath
|
||||
io.grpc:grpc-services:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath
|
||||
io.grpc:grpc-services:1.81.0=testRuntimeClasspath
|
||||
io.grpc:grpc-stub:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.grpc:grpc-stub:1.81.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-util:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath
|
||||
io.grpc:grpc-util:1.81.0=testRuntimeClasspath
|
||||
io.grpc:grpc-xds:1.76.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath
|
||||
io.grpc:grpc-xds:1.81.0=testRuntimeClasspath
|
||||
io.grpc:grpc-services:1.76.3=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
io.grpc:grpc-services:1.81.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-stub:1.81.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-util:1.76.3=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
io.grpc:grpc-util:1.81.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-xds:1.76.3=compileClasspath,nonprodCompileClasspath,testCompileClasspath
|
||||
io.grpc:grpc-xds:1.81.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
io.netty:netty-buffer:4.1.124.Final=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.netty:netty-codec-http2:4.1.124.Final=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.netty:netty-codec-http:4.1.124.Final=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -302,8 +292,8 @@ io.opencensus:opencensus-exporter-metrics-util:0.31.0=compileClasspath,deploy_ja
|
||||
io.opencensus:opencensus-exporter-stats-stackdriver:0.31.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.opencensus:opencensus-impl-core:0.31.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.opencensus:opencensus-impl:0.31.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.opentelemetry.contrib:opentelemetry-gcp-resources:1.37.0-alpha=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.opentelemetry.contrib:opentelemetry-gcp-resources:1.45.0-alpha=testCompileClasspath,testRuntimeClasspath
|
||||
io.opentelemetry.contrib:opentelemetry-gcp-resources:1.37.0-alpha=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
io.opentelemetry.contrib:opentelemetry-gcp-resources:1.45.0-alpha=testCompileClasspath
|
||||
io.opentelemetry.instrumentation:opentelemetry-grpc-1.6:2.1.0-alpha=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.opentelemetry.instrumentation:opentelemetry-instrumentation-api-incubator:2.1.0-alpha=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
io.opentelemetry.instrumentation:opentelemetry-instrumentation-api:2.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -318,7 +308,7 @@ io.opentelemetry:opentelemetry-exporter-logging:1.62.0=testCompileClasspath,test
|
||||
io.opentelemetry:opentelemetry-extension-incubator:1.35.0-alpha=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
io.opentelemetry:opentelemetry-sdk-common:1.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.opentelemetry:opentelemetry-sdk-common:1.62.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:1.47.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:1.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:1.62.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:1.62.0=testCompileClasspath,testRuntimeClasspath
|
||||
io.opentelemetry:opentelemetry-sdk-logs:1.51.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
@@ -342,7 +332,8 @@ jakarta.activation:jakarta.activation-api:2.2.0-M2=compileClasspath,nonprodCompi
|
||||
jakarta.inject:jakarta.inject-api:2.0.1=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
jakarta.mail:jakarta.mail-api:2.2.0-M1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
jakarta.persistence:jakarta.persistence-api:3.2.0=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
jakarta.servlet:jakarta.servlet-api:6.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
jakarta.servlet:jakarta.servlet-api:6.0.0=testCompileClasspath,testRuntimeClasspath
|
||||
jakarta.servlet:jakarta.servlet-api:6.2.0-M2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
jakarta.transaction:jakarta.transaction-api:2.0.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
jakarta.xml.bind:jakarta.xml.bind-api:4.0.4=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
jakarta.xml.bind:jakarta.xml.bind-api:4.0.5=jaxb
|
||||
@@ -350,7 +341,6 @@ jakarta.xml.bind:jakarta.xml.bind-api:4.1.0-M1=compileClasspath,nonprodCompileCl
|
||||
javax.annotation:javax.annotation-api:1.3.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
javax.inject:javax.inject:1=annotationProcessor,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
javax.jdo:jdo2-api:2.3-20090302111651=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
javax.validation:validation-api:1.0.0.GA=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
joda-time:joda-time:2.14.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
junit:junit:4.13.2=nonprodCompileClasspath,nonprodRuntimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
net.arnx:nashorn-promise:0.1.1=testRuntimeClasspath
|
||||
@@ -370,24 +360,24 @@ org.apache.arrow:arrow-format:17.0.0=compileClasspath,deploy_jar,nonprodCompileC
|
||||
org.apache.arrow:arrow-memory-core:17.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.arrow:arrow-vector:17.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.avro:avro:1.11.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-model-fn-execution:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-model-job-management:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-model-pipeline:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-model-fn-execution:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-model-job-management:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-model-pipeline:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-runners-core-construction-java:2.54.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-runners-core-java:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-runners-direct-java:2.72.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-runners-java-fn-execution:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-core:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-expansion-service:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-extensions-arrow:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-extensions-avro:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-extensions-protobuf:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-runners-core-java:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-runners-direct-java:2.73.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-runners-java-fn-execution:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-core:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-expansion-service:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-extensions-arrow:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-extensions-avro:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-extensions-protobuf:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-fn-execution:2.54.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-harness:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-transform-service-launcher:2.72.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-harness:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-sdks-java-transform-service-launcher:2.73.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-vendor-grpc-1_60_1:0.1=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-vendor-grpc-1_69_0:0.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.beam:beam-vendor-guava-32_1_2-jre:0.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -397,7 +387,7 @@ org.apache.commons:commons-exec:1.3=testRuntimeClasspath
|
||||
org.apache.commons:commons-lang3:3.18.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
org.apache.commons:commons-lang3:3.20.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.commons:commons-lang3:3.8.1=checkstyle
|
||||
org.apache.commons:commons-pool2:2.12.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.commons:commons-pool2:2.13.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.commons:commons-text:1.15.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.commons:commons-text:1.3=checkstyle
|
||||
org.apache.ftpserver:ftplet-api:1.2.1=testCompileClasspath,testRuntimeClasspath
|
||||
@@ -414,10 +404,10 @@ org.apache.maven.doxia:doxia-logging-api:1.12.0=checkstyle
|
||||
org.apache.maven.doxia:doxia-module-xdoc:1.12.0=checkstyle
|
||||
org.apache.maven.doxia:doxia-sink-api:1.12.0=checkstyle
|
||||
org.apache.mina:mina-core:2.2.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.sshd:sshd-common:3.0.0-M3=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.sshd:sshd-core:3.0.0-M3=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.sshd:sshd-scp:3.0.0-M3=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.sshd:sshd-sftp:3.0.0-M3=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.sshd:sshd-common:3.0.0-M4=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.sshd:sshd-core:3.0.0-M4=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.sshd:sshd-scp:3.0.0-M4=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.sshd:sshd-sftp:3.0.0-M4=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.tomcat:tomcat-annotations-api:11.0.22=testCompileClasspath,testRuntimeClasspath
|
||||
org.apache.xbean:xbean-reflect:3.7=checkstyle
|
||||
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath
|
||||
@@ -430,13 +420,12 @@ org.checkerframework:checker-compat-qual:2.5.6=deploy_jar,nonprodRuntimeClasspat
|
||||
org.checkerframework:checker-qual:3.19.0=annotationProcessor,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.checkerframework:checker-qual:3.49.3=checkstyle
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.24=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.27=testCompileClasspath,testRuntimeClasspath
|
||||
org.codehaus.mojo:animal-sniffer-annotations:1.27=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.codehaus.plexus:plexus-classworlds:2.6.0=checkstyle
|
||||
org.codehaus.plexus:plexus-component-annotations:2.1.0=checkstyle
|
||||
org.codehaus.plexus:plexus-container-default:2.1.0=checkstyle
|
||||
org.codehaus.plexus:plexus-utils:3.3.0=checkstyle
|
||||
org.codehaus.woodstox:stax2-api:4.2.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.codehaus.woodstox:stax2-api:4.2.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.conscrypt:conscrypt-openjdk-uber:2.5.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.angus:angus-activation:2.0.3=jaxb
|
||||
org.eclipse.angus:angus-activation:2.1.0-M1=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
@@ -451,19 +440,18 @@ org.eclipse.jetty:jetty-server:12.1.9=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-session:12.1.9=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-util:12.1.9=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-xml:12.1.9=testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:12.6.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:12.6.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:12.7.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:12.7.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.freemarker:freemarker:2.3.34=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:codemodel:4.0.8=jaxb
|
||||
org.glassfish.jaxb:codemodel:4.0.9=jaxb
|
||||
org.glassfish.jaxb:jaxb-core:4.0.6=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:jaxb-core:4.0.8=jaxb
|
||||
org.glassfish.jaxb:jaxb-core:4.0.9=jaxb
|
||||
org.glassfish.jaxb:jaxb-runtime:4.0.6=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:jaxb-runtime:4.0.8=jaxb
|
||||
org.glassfish.jaxb:jaxb-xjc:4.0.8=jaxb
|
||||
org.glassfish.jaxb:jaxb-runtime:4.0.9=jaxb
|
||||
org.glassfish.jaxb:jaxb-xjc:4.0.9=jaxb
|
||||
org.glassfish.jaxb:txw2:4.0.6=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:txw2:4.0.8=jaxb
|
||||
org.glassfish.jaxb:xsom:4.0.8=jaxb
|
||||
org.gwtproject:gwt-user:2.10.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:txw2:4.0.9=jaxb
|
||||
org.glassfish.jaxb:xsom:4.0.9=jaxb
|
||||
org.hamcrest:hamcrest-core:1.3=nonprodCompileClasspath,nonprodRuntimeClasspath
|
||||
org.hamcrest:hamcrest-core:3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.hamcrest:hamcrest-library:3.0=testCompileClasspath,testRuntimeClasspath
|
||||
@@ -479,18 +467,18 @@ org.jacoco:org.jacoco.core:0.8.14=jacocoAnt
|
||||
org.jacoco:org.jacoco.report:0.8.14=jacocoAnt
|
||||
org.javassist:javassist:3.28.0-GA=checkstyle
|
||||
org.jboss.logging:jboss-logging:3.6.3.Final=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.jcommander:jcommander:2.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jcommander:jcommander:3.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-bom:1.4.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-metadata-jvm:2.2.20=annotationProcessor,testAnnotationProcessor
|
||||
org.jetbrains.kotlin:kotlin-reflect:1.6.10=annotationProcessor,testAnnotationProcessor
|
||||
org.jetbrains.kotlin:kotlin-reflect:1.9.20=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-common:1.9.20=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-common:2.2.21=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0=annotationProcessor,testAnnotationProcessor
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.10=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0=annotationProcessor,testAnnotationProcessor
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.10=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib:1.9.20=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jetbrains.kotlin:kotlin-stdlib:2.2.20=annotationProcessor,testAnnotationProcessor
|
||||
org.jetbrains.kotlin:kotlin-stdlib:2.2.21=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.2=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.4.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -499,23 +487,25 @@ org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.0.1=deploy_jar,nonprodRun
|
||||
org.jetbrains.kotlinx:kotlinx-serialization-core:1.0.1=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.jetbrains:annotations:13.0=annotationProcessor,testAnnotationProcessor
|
||||
org.jetbrains:annotations:17.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jline:jline:3.30.5=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jline:jline:4.1.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.joda:joda-money:2.0.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.json:json:20251224=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.json:json:20260522=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jsoup:jsoup:1.22.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jspecify:jspecify:1.0.0=annotationProcessor,checkstyle,compileClasspath,deploy_jar,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
org.junit-pioneer:junit-pioneer:2.3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-api:5.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-engine:5.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:5.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-params:5.13.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-commons:1.14.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-engine:1.14.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-launcher:1.14.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-runner:1.13.3=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-suite-api:1.14.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-api:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-engine:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-migrationsupport:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.jupiter:junit-jupiter-params:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-commons:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-engine:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-launcher:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-runner:1.14.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-suite-api:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-suite-commons:1.14.4=testRuntimeClasspath
|
||||
org.junit:junit-bom:5.14.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-suite-engine:6.1.0=testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-suite:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit:junit-bom:6.1.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.mockito:mockito-core:5.23.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.mockito:mockito-junit-jupiter:5.23.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.objenesis:objenesis:3.3=testRuntimeClasspath
|
||||
@@ -553,7 +543,7 @@ org.seleniumhq.selenium:selenium-safari-driver:4.44.0=testCompileClasspath,testR
|
||||
org.seleniumhq.selenium:selenium-support:4.44.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.slf4j:jcl-over-slf4j:1.7.36=testCompileClasspath,testRuntimeClasspath
|
||||
org.slf4j:jul-to-slf4j:1.7.30=testRuntimeClasspath
|
||||
org.slf4j:slf4j-api:2.0.17=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.slf4j:slf4j-api:2.0.18=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.slf4j:slf4j-jdk14:2.0.17=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.snakeyaml:snakeyaml-engine:2.1=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.testcontainers:database-commons:1.21.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -563,13 +553,12 @@ org.testcontainers:postgresql:1.21.4=compileClasspath,deploy_jar,nonprodCompileC
|
||||
org.testcontainers:selenium:1.21.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.testcontainers:testcontainers:1.21.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.threeten:threetenbp:1.7.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.w3c.css:sac:1.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.webjars.npm:viz.js-graphviz-java:2.1.3=testRuntimeClasspath
|
||||
org.xerial.snappy:snappy-java:1.1.10.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.xmlresolver:xmlresolver:5.2.2=checkstyle
|
||||
org.yaml:snakeyaml:2.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.yaml:snakeyaml:2.5=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
redis.clients.authentication:redis-authx-core:0.1.1-beta2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
redis.clients:jedis:7.4.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
redis.clients:jedis:8.0.0-beta1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
tools.jackson.core:jackson-core:3.1.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
tools.jackson.core:jackson-databind:3.1.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
tools.jackson:jackson-bom:3.1.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
|
||||
@@ -212,17 +212,16 @@ public class RdeIO {
|
||||
}
|
||||
}
|
||||
|
||||
// Don't write the IDN elements for BRDA.
|
||||
// Don't write the IDN elements or EPP params for BRDA.
|
||||
if (mode == RdeMode.FULL) {
|
||||
for (IdnTableEnum idn : IdnTableEnum.values()) {
|
||||
output.write(marshaller.marshalIdn(idn.getTable()));
|
||||
counter.increment(RdeResourceType.IDN);
|
||||
}
|
||||
output.write(marshaller.marshalRdeEppParams());
|
||||
counter.increment(RdeResourceType.EPP_PARAMS);
|
||||
}
|
||||
|
||||
output.write(marshaller.marshalRdeEppParams());
|
||||
counter.increment(RdeResourceType.EPP_PARAMS);
|
||||
|
||||
// Output XML that says how many resources were emitted.
|
||||
header = counter.makeHeader(tld, mode);
|
||||
output.write(marshaller.marshalOrDie(new XjcRdeHeaderElement(header)));
|
||||
|
||||
@@ -372,7 +372,7 @@ public class RdePipeline implements Serializable {
|
||||
* <p>The (repoId, pendingDeposit) pairs denote hosts that are referenced from a domain, that are
|
||||
* to be included in the corresponding pending deposit.
|
||||
*
|
||||
* <p>The (repoId, revisionId) paris come from the most recent history entry query, which can be
|
||||
* <p>The (repoId, revisionId) pairs come from the most recent history entry query, which can be
|
||||
* used to load the embedded resources themselves.
|
||||
*
|
||||
* @return a pair of (repoId, ([pendingDeposit], [revisionId])) where neither the pendingDeposit
|
||||
|
||||
@@ -25,10 +25,20 @@ import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.host.Host;
|
||||
import io.protostuff.Input;
|
||||
import io.protostuff.LinkedBuffer;
|
||||
import io.protostuff.Output;
|
||||
import io.protostuff.Pipe;
|
||||
import io.protostuff.ProtostuffIOUtil;
|
||||
import io.protostuff.Schema;
|
||||
import io.protostuff.WireFormat;
|
||||
import io.protostuff.runtime.DefaultIdStrategy;
|
||||
import io.protostuff.runtime.Delegate;
|
||||
import io.protostuff.runtime.RuntimeSchema;
|
||||
import java.io.IOException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Optional;
|
||||
import redis.clients.jedis.AbstractPipeline;
|
||||
@@ -52,11 +62,20 @@ public class SimplifiedJedisClient {
|
||||
Domain.class, "d_",
|
||||
Host.class, "h_");
|
||||
|
||||
/** We need to inform Protostuff of the custom {@link InetAddress} delegates. */
|
||||
private static DefaultIdStrategy createIdStrategy() {
|
||||
DefaultIdStrategy strategy = new DefaultIdStrategy();
|
||||
strategy.registerDelegate(new GenericInetAddressDelegate<>(InetAddress.class));
|
||||
strategy.registerDelegate(new GenericInetAddressDelegate<>(Inet4Address.class));
|
||||
strategy.registerDelegate(new GenericInetAddressDelegate<>(Inet6Address.class));
|
||||
return strategy;
|
||||
}
|
||||
|
||||
private static final ImmutableMap<Class<? extends EppResource>, Schema<? extends EppResource>>
|
||||
VALUE_SCHEMAS =
|
||||
ImmutableMap.of(
|
||||
Domain.class, RuntimeSchema.getSchema(Domain.class),
|
||||
Host.class, RuntimeSchema.getSchema(Host.class));
|
||||
Host.class, RuntimeSchema.getSchema(Host.class, createIdStrategy()));
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
@@ -151,4 +170,46 @@ public class SimplifiedJedisClient {
|
||||
checkArgument(VALUE_SCHEMAS.containsKey(clazz), "Unknown class type %s", clazz);
|
||||
return (Schema<V>) VALUE_SCHEMAS.get(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* A custom Protostuff {@link Delegate} for {@link InetAddress} and its subclasses.
|
||||
*
|
||||
* <p>This is required in Java 17+ because Protostuff's default runtime schema serialization
|
||||
* relies on reflection. Since {@link InetAddress} is part of the encapsulated {@code java.base}
|
||||
* module, reflective access is restricted and throws {@link
|
||||
* java.lang.reflect.InaccessibleObjectException}.
|
||||
*
|
||||
* <p>This delegate serializes the IP address as a raw byte array using {@link
|
||||
* InetAddress#getAddress()} and reconstructs it using {@link InetAddress#getByAddress(byte[])}
|
||||
*/
|
||||
private record GenericInetAddressDelegate<T extends InetAddress>(Class<T> clazz)
|
||||
implements Delegate<T> {
|
||||
|
||||
@Override
|
||||
public WireFormat.FieldType getFieldType() {
|
||||
return WireFormat.FieldType.BYTES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> typeClass() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T readFrom(Input input) throws IOException {
|
||||
return (T) InetAddress.getByAddress(input.readByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(Output output, int number, T value, boolean repeated) throws IOException {
|
||||
output.writeByteArray(number, value.getAddress(), repeated);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transfer(Pipe pipe, Input input, Output output, int number, boolean repeated)
|
||||
throws IOException {
|
||||
output.writeByteArray(number, input.readByteArray(), repeated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,6 +173,18 @@ public final class RegistryConfig {
|
||||
return config.registrarConsole.supportEmailAddress;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("consoleHistoryQueryLimit")
|
||||
public static int provideConsoleHistoryQueryLimit(RegistryConfigSettings config) {
|
||||
return config.registrarConsole.historyQueryLimit;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("consoleBulkDomainActionLimit")
|
||||
public static int provideConsoleBulkDomainActionLimit(RegistryConfigSettings config) {
|
||||
return config.registrarConsole.bulkDomainActionLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* The DUM file name, used as a file name base for DUM csv file
|
||||
*
|
||||
|
||||
@@ -181,6 +181,8 @@ public class RegistryConfigSettings {
|
||||
public String supportPhoneNumber;
|
||||
public String supportEmailAddress;
|
||||
public String technicalDocsUrl;
|
||||
public int historyQueryLimit;
|
||||
public int bulkDomainActionLimit;
|
||||
}
|
||||
|
||||
/** Configuration for monitoring. */
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
<queue>
|
||||
<name>dns-refresh</name>
|
||||
<max-dispatches-per-second>100</max-dispatches-per-second>
|
||||
<max-retry-duration>82800s</max-retry-duration>
|
||||
</queue>
|
||||
|
||||
<!-- Queue for publishing DNS updates in batches. -->
|
||||
@@ -29,6 +30,7 @@
|
||||
<min-backoff>30s</min-backoff>
|
||||
<max-backoff>1800s</max-backoff>
|
||||
<max-doublings>0</max-doublings>
|
||||
<max-retry-duration>82800s</max-retry-duration>
|
||||
</queue>
|
||||
|
||||
<!-- Queue for uploading RDE deposits to the escrow provider. -->
|
||||
@@ -59,6 +61,7 @@
|
||||
<queue>
|
||||
<name>async-host-rename</name>
|
||||
<max-dispatches-per-second>1</max-dispatches-per-second>
|
||||
<max-retry-duration>82800s</max-retry-duration>
|
||||
</queue>
|
||||
|
||||
<!-- Queue for tasks that wait for a Beam pipeline to complete (i.e. Spec11 and invoicing). -->
|
||||
@@ -110,11 +113,12 @@
|
||||
<max-attempts>3</max-attempts>
|
||||
</queue>
|
||||
|
||||
<!-- <!– Queue for async actions that should be run at some point in the future. –>-->
|
||||
<!-- Queue for async actions that should be run at some point in the future.-->
|
||||
<queue>
|
||||
<name>async-actions</name>
|
||||
<max-dispatches-per-second>1</max-dispatches-per-second>
|
||||
<max-concurrent-dispatches>5</max-concurrent-dispatches>
|
||||
<max-retry-duration>82800s</max-retry-duration>
|
||||
</queue>
|
||||
|
||||
</entries>
|
||||
|
||||
@@ -380,6 +380,12 @@ registrarConsole:
|
||||
# URL linking to directory of technical support docs on the registry.
|
||||
technicalDocsUrl: http://example.com/your_support_docs/
|
||||
|
||||
# Maximum number of history records returned in a single query.
|
||||
historyQueryLimit: 500
|
||||
|
||||
# Maximum number of domains allowed in a single bulk action.
|
||||
bulkDomainActionLimit: 500
|
||||
|
||||
monitoring:
|
||||
# Max queries per second for the Google Cloud Monitoring V3 (aka Stackdriver)
|
||||
# API. The limit can be adjusted by contacting Cloud Support.
|
||||
|
||||
-10
@@ -266,16 +266,6 @@
|
||||
<schedule>0 15 * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/wipeOutContactHistoryPii]]></url>
|
||||
<name>wipeOutContactHistoryPii</name>
|
||||
<description>
|
||||
This job runs weekly to wipe out PII fields of ContactHistory entities
|
||||
that have been in the database for a certain period of time.
|
||||
</description>
|
||||
<schedule>0 15 * * 1</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/bsaDownload]]></url>
|
||||
<name>bsaDownload</name>
|
||||
|
||||
-10
@@ -155,16 +155,6 @@
|
||||
<schedule>*/1 * * * *</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/wipeOutContactHistoryPii]]></url>
|
||||
<name>wipeOutContactHistoryPii</name>
|
||||
<description>
|
||||
This job runs weekly to wipe out PII fields of ContactHistory entities
|
||||
that have been in the database for a certain period of time.
|
||||
</description>
|
||||
<schedule>0 15 * * 1</schedule>
|
||||
</task>
|
||||
|
||||
<task>
|
||||
<url><![CDATA[/_dr/task/bsaDownload]]></url>
|
||||
<name>bsaDownload</name>
|
||||
|
||||
@@ -36,13 +36,13 @@ import static google.registry.persistence.PersistenceModule.TransactionIsolation
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
|
||||
import static google.registry.pricing.PricingEngineProxy.isDomainPremium;
|
||||
import static google.registry.util.DomainNameUtils.canonicalizeHostname;
|
||||
import static org.json.simple.JSONValue.toJSONString;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.gson.Gson;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.flows.domain.DomainFlowUtils.BadCommandForRegistryPhaseException;
|
||||
@@ -83,6 +83,7 @@ public class CheckApiAction implements Runnable {
|
||||
@Inject Response response;
|
||||
@Inject CheckApiMetric.Builder metricBuilder;
|
||||
@Inject CheckApiMetrics checkApiMetrics;
|
||||
@Inject Gson gson;
|
||||
|
||||
@Inject
|
||||
CheckApiAction() {}
|
||||
@@ -94,7 +95,7 @@ public class CheckApiAction implements Runnable {
|
||||
response.setHeader("X-Content-Type-Options", "nosniff");
|
||||
response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
|
||||
response.setContentType(MediaType.JSON_UTF_8);
|
||||
response.setPayload(toJSONString(doCheck()));
|
||||
response.setPayload(gson.toJson(doCheck()));
|
||||
} finally {
|
||||
CheckApiMetric metric = metricBuilder.build();
|
||||
checkApiMetrics.incrementCheckApiRequest(metric);
|
||||
|
||||
@@ -24,6 +24,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.flows.FlowModule.EppExceptionInProviderException;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
@@ -34,7 +35,6 @@ import google.registry.model.eppoutput.Result.Code;
|
||||
import google.registry.monitoring.whitebox.EppMetric;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.Optional;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
/**
|
||||
* An implementation of the EPP command/response protocol.
|
||||
@@ -50,6 +50,8 @@ public final class EppController {
|
||||
@Inject EppMetric.Builder eppMetricBuilder;
|
||||
@Inject EppMetrics eppMetrics;
|
||||
@Inject ServerTridProvider serverTridProvider;
|
||||
@Inject Gson gson;
|
||||
|
||||
@Inject EppController() {}
|
||||
|
||||
/** Reads EPP XML, executes the matching flow, and returns an {@link EppOutput}. */
|
||||
@@ -72,7 +74,7 @@ public final class EppController {
|
||||
e.getMessage(),
|
||||
lazy(
|
||||
() ->
|
||||
JSONValue.toJSONString(
|
||||
gson.toJson(
|
||||
ImmutableMap.<String, Object>of(
|
||||
"clientId",
|
||||
nullToEmpty(sessionMetadata.getRegistrarId()),
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.flows.FlowModule.InputXml;
|
||||
import google.registry.flows.FlowModule.RegistrarId;
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
@@ -30,7 +31,6 @@ import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import jakarta.inject.Inject;
|
||||
import java.util.Optional;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
/** Reporter used by {@link FlowRunner} to record flow execution data for reporting. */
|
||||
public class FlowReporter {
|
||||
@@ -49,6 +49,8 @@ public class FlowReporter {
|
||||
@Inject @InputXml byte[] inputXmlBytes;
|
||||
@Inject EppInput eppInput;
|
||||
@Inject Class<? extends Flow> flowClass;
|
||||
@Inject Gson gson;
|
||||
|
||||
@Inject FlowReporter() {}
|
||||
|
||||
/** Records information about the current flow execution in the request logs. */
|
||||
@@ -61,7 +63,7 @@ public class FlowReporter {
|
||||
logger.atInfo().log(
|
||||
"%s: %s",
|
||||
METADATA_LOG_SIGNATURE,
|
||||
JSONValue.toJSONString(
|
||||
gson.toJson(
|
||||
new ImmutableMap.Builder<String, Object>()
|
||||
.put("serverTrid", trid.getServerTransactionId())
|
||||
.put("clientId", registrarId)
|
||||
|
||||
@@ -44,6 +44,8 @@ import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.model.transfer.TransferStatus;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -134,7 +136,9 @@ public final class ResourceFlowUtils {
|
||||
}
|
||||
String authPassword = authInfo.getPw().getValue();
|
||||
String domainPassword = domain.getAuthInfo().getPw().getValue();
|
||||
if (!domainPassword.equals(authPassword)) {
|
||||
if (!MessageDigest.isEqual(
|
||||
authPassword.getBytes(StandardCharsets.UTF_8),
|
||||
domainPassword.getBytes(StandardCharsets.UTF_8))) {
|
||||
throw new BadAuthInfoForResourceException();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,9 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMark verifySignedMarks(
|
||||
ImmutableList<AbstractSignedMark> signedMarks, String domainLabel, Instant now)
|
||||
throws EppException {
|
||||
if (signedMarks.isEmpty()) {
|
||||
throw new SignedMarksListEmptyException();
|
||||
}
|
||||
if (signedMarks.size() > 1) {
|
||||
throw new TooManySignedMarksException();
|
||||
}
|
||||
@@ -77,21 +80,21 @@ public final class DomainFlowTmchUtils {
|
||||
|
||||
public SignedMark verifyEncodedSignedMark(EncodedSignedMark encodedSignedMark, Instant now)
|
||||
throws EppException {
|
||||
if (!encodedSignedMark.getEncoding().equals("base64")) {
|
||||
if (!"base64".equals(encodedSignedMark.getEncoding())) {
|
||||
throw new Base64RequiredForEncodedSignedMarksException();
|
||||
}
|
||||
byte[] signedMarkData;
|
||||
try {
|
||||
signedMarkData = encodedSignedMark.getBytes();
|
||||
} catch (IllegalStateException e) {
|
||||
throw new SignedMarkEncodingErrorException();
|
||||
throw new SignedMarkEncodingErrorException(e);
|
||||
}
|
||||
|
||||
SignedMark signedMark;
|
||||
try {
|
||||
signedMark = unmarshalEpp(SignedMark.class, signedMarkData);
|
||||
} catch (EppException e) {
|
||||
throw new SignedMarkParsingErrorException();
|
||||
throw new SignedMarkParsingErrorException(e);
|
||||
}
|
||||
|
||||
if (SignedMarkRevocationList.get().isSmdRevoked(signedMark.getId(), now)) {
|
||||
@@ -101,22 +104,22 @@ public final class DomainFlowTmchUtils {
|
||||
try {
|
||||
tmchXmlSignature.verify(signedMarkData);
|
||||
} catch (CertificateExpiredException e) {
|
||||
throw new SignedMarkCertificateExpiredException();
|
||||
throw new SignedMarkCertificateExpiredException(e);
|
||||
} catch (CertificateNotYetValidException e) {
|
||||
throw new SignedMarkCertificateNotYetValidException();
|
||||
throw new SignedMarkCertificateNotYetValidException(e);
|
||||
} catch (CertificateRevokedException e) {
|
||||
throw new SignedMarkCertificateRevokedException();
|
||||
throw new SignedMarkCertificateRevokedException(e);
|
||||
} catch (CertificateSignatureException e) {
|
||||
throw new SignedMarkCertificateSignatureException();
|
||||
throw new SignedMarkCertificateSignatureException(e);
|
||||
} catch (SignatureException | XMLSignatureException e) {
|
||||
throw new SignedMarkSignatureException();
|
||||
throw new SignedMarkSignatureException(e);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new SignedMarkCertificateInvalidException();
|
||||
throw new SignedMarkCertificateInvalidException(e);
|
||||
} catch (IOException
|
||||
| MarshalException
|
||||
| SAXException
|
||||
| ParserConfigurationException e) {
|
||||
throw new SignedMarkParsingErrorException();
|
||||
throw new SignedMarkParsingErrorException(e);
|
||||
}
|
||||
|
||||
if (now.isBefore(signedMark.getCreationTime())) {
|
||||
@@ -181,6 +184,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkCertificateRevokedException() {
|
||||
super("Signed mark certificate was revoked");
|
||||
}
|
||||
|
||||
public SignedMarkCertificateRevokedException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Certificate used in signed mark signature has expired. */
|
||||
@@ -189,6 +197,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkCertificateNotYetValidException() {
|
||||
super("Signed mark certificate not yet valid");
|
||||
}
|
||||
|
||||
public SignedMarkCertificateNotYetValidException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Certificate used in signed mark signature has expired. */
|
||||
@@ -196,6 +209,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkCertificateExpiredException() {
|
||||
super("Signed mark certificate has expired");
|
||||
}
|
||||
|
||||
public SignedMarkCertificateExpiredException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Certificate parsing error, or possibly a bad provider or algorithm. */
|
||||
@@ -203,6 +221,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkCertificateInvalidException() {
|
||||
super("Signed mark certificate is invalid");
|
||||
}
|
||||
|
||||
public SignedMarkCertificateInvalidException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Invalid signature on a signed mark. */
|
||||
@@ -210,6 +233,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkCertificateSignatureException() {
|
||||
super("Signed mark certificate not signed by ICANN");
|
||||
}
|
||||
|
||||
public SignedMarkCertificateSignatureException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Invalid signature on a signed mark. */
|
||||
@@ -217,6 +245,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkSignatureException() {
|
||||
super("Signed mark signature is invalid");
|
||||
}
|
||||
|
||||
public SignedMarkSignatureException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Signed marks must be encoded. */
|
||||
@@ -226,6 +259,13 @@ public final class DomainFlowTmchUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/** Signed marks list cannot be empty. */
|
||||
static class SignedMarksListEmptyException extends RequiredParameterMissingException {
|
||||
public SignedMarksListEmptyException() {
|
||||
super("Signed marks list cannot be empty");
|
||||
}
|
||||
}
|
||||
|
||||
/** Only one signed mark is allowed per application. */
|
||||
static class TooManySignedMarksException extends ParameterValuePolicyErrorException {
|
||||
public TooManySignedMarksException() {
|
||||
@@ -245,6 +285,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkParsingErrorException() {
|
||||
super("Error while parsing encoded signed mark data");
|
||||
}
|
||||
|
||||
public SignedMarkParsingErrorException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
/** Signed mark data is improperly encoded. */
|
||||
@@ -252,6 +297,11 @@ public final class DomainFlowTmchUtils {
|
||||
public SignedMarkEncodingErrorException() {
|
||||
super("Signed mark data is improperly encoded");
|
||||
}
|
||||
|
||||
public SignedMarkEncodingErrorException(Throwable cause) {
|
||||
this();
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import static com.google.common.collect.Sets.difference;
|
||||
import static com.google.common.collect.Sets.intersection;
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static google.registry.bsa.persistence.BsaLabelUtils.isLabelBlocked;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureName.FORBID_INSECURE_ALGORITHMS_RFC_9904;
|
||||
import static google.registry.model.domain.Domain.MAX_REGISTRATION_YEARS;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.REGISTER_BSA;
|
||||
import static google.registry.model.tld.Tld.TldState.GENERAL_AVAILABILITY;
|
||||
@@ -73,6 +74,7 @@ import google.registry.model.EppResource;
|
||||
import google.registry.model.billing.BillingBase.Flag;
|
||||
import google.registry.model.billing.BillingBase.Reason;
|
||||
import google.registry.model.billing.BillingRecurrence;
|
||||
import google.registry.model.common.FeatureFlag;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainCommand.Create;
|
||||
import google.registry.model.domain.DomainCommand.CreateOrUpdate;
|
||||
@@ -341,7 +343,7 @@ public class DomainFlowUtils {
|
||||
}
|
||||
ImmutableList<DomainDsData> invalidAlgorithms =
|
||||
dsData.stream()
|
||||
.filter(ds -> !validateAlgorithm(ds.getAlgorithm()))
|
||||
.filter(ds -> algorithmIsInvalid(ds.getAlgorithm()))
|
||||
.collect(toImmutableList());
|
||||
if (!invalidAlgorithms.isEmpty()) {
|
||||
throw new InvalidDsRecordException(
|
||||
@@ -349,9 +351,16 @@ public class DomainFlowUtils {
|
||||
"Domain contains DS record(s) with an invalid algorithm wire value: %s",
|
||||
invalidAlgorithms));
|
||||
}
|
||||
boolean forbidInsecureTypes = FeatureFlag.isActiveNow(FORBID_INSECURE_ALGORITHMS_RFC_9904);
|
||||
ImmutableList<DomainDsData> invalidDigestTypes =
|
||||
dsData.stream()
|
||||
.filter(ds -> DigestType.fromWireValue(ds.getDigestType()).isEmpty())
|
||||
.filter(
|
||||
ds -> {
|
||||
Optional<DigestType> digestType = DigestType.fromWireValue(ds.getDigestType());
|
||||
return digestType
|
||||
.map(type -> forbidInsecureTypes && !type.isAllowedInRfc9904())
|
||||
.orElse(true);
|
||||
})
|
||||
.collect(toImmutableList());
|
||||
if (!invalidDigestTypes.isEmpty()) {
|
||||
throw new InvalidDsRecordException(
|
||||
@@ -376,14 +385,18 @@ public class DomainFlowUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean validateAlgorithm(int alg) {
|
||||
public static boolean algorithmIsInvalid(int alg) {
|
||||
if (alg > 255 || alg < 0) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
if (DomainDsData.FORBIDDEN_ALGORITHMS.contains(alg)
|
||||
&& FeatureFlag.isActiveNow(FORBID_INSECURE_ALGORITHMS_RFC_9904)) {
|
||||
return true;
|
||||
}
|
||||
// Algorithms that are reserved or unassigned will just return a string representation of their
|
||||
// integer wire value.
|
||||
String algorithm = Algorithm.string(alg);
|
||||
return !algorithm.equals(Integer.toString(alg));
|
||||
return algorithm.equals(Integer.toString(alg));
|
||||
}
|
||||
|
||||
/** We only allow specifying years in a period. */
|
||||
|
||||
@@ -283,7 +283,7 @@ public final class DomainPricingLogic {
|
||||
return tld.getStandardRenewCost(dateTime).multipliedBy(years);
|
||||
}
|
||||
if (token.getRenewalPriceBehavior().equals(RenewalPriceBehavior.SPECIFIED)) {
|
||||
return token.getRenewalPrice().get();
|
||||
return token.getRenewalPrice().get().multipliedBy(years);
|
||||
}
|
||||
}
|
||||
return getDomainCostWithDiscount(
|
||||
@@ -328,12 +328,13 @@ public final class DomainPricingLogic {
|
||||
// Apply the allocation token discount, if applicable.
|
||||
if (token.getDiscountPrice().isPresent()
|
||||
&& tld.getCurrency().equals(token.getDiscountPrice().get().getCurrencyUnit())) {
|
||||
int nonDiscountedYears = Math.max(0, years - token.getDiscountYears());
|
||||
int discountedYears = Math.min(years, token.getDiscountYears());
|
||||
int nonDiscountedYears = years - discountedYears;
|
||||
totalDomainFlowCost =
|
||||
token
|
||||
.getDiscountPrice()
|
||||
.get()
|
||||
.multipliedBy(token.getDiscountYears())
|
||||
.multipliedBy(discountedYears)
|
||||
.plus(subsequentYearCost.orElse(firstYearCost).multipliedBy(nonDiscountedYears));
|
||||
} else if (token.getDiscountFraction() > 0) {
|
||||
int discountedYears = Math.min(years, token.getDiscountYears());
|
||||
|
||||
@@ -116,15 +116,21 @@ public class HostFlowUtils {
|
||||
if (inetAddresses == null) {
|
||||
return;
|
||||
}
|
||||
if (inetAddresses.stream().anyMatch(InetAddress::isLoopbackAddress)) {
|
||||
throw new LoopbackIpNotValidForHostException();
|
||||
for (InetAddress inetAddress : inetAddresses) {
|
||||
if (inetAddress.isLoopbackAddress()
|
||||
|| inetAddress.isLinkLocalAddress()
|
||||
|| inetAddress.isSiteLocalAddress()
|
||||
|| inetAddress.isAnyLocalAddress()
|
||||
|| inetAddress.isMulticastAddress()) {
|
||||
throw new IpAddressNotRoutableException(inetAddress.getHostAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Loopback IPs are not valid for hosts. */
|
||||
static class LoopbackIpNotValidForHostException extends ParameterValuePolicyErrorException {
|
||||
public LoopbackIpNotValidForHostException() {
|
||||
super("Loopback IPs are not valid for hosts");
|
||||
/** IP address is not a public, routable address. */
|
||||
static class IpAddressNotRoutableException extends ParameterValuePolicyErrorException {
|
||||
public IpAddressNotRoutableException(String ipAddress) {
|
||||
super(String.format("IP address %s is not a public, globally routable address", ipAddress));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.flows.picker;
|
||||
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableTable;
|
||||
@@ -255,6 +256,17 @@ public class FlowPicker {
|
||||
if (innerCommand == null && !(eppInput.getCommandWrapper() instanceof Hello)) {
|
||||
throw new MissingCommandException();
|
||||
}
|
||||
if (innerCommand instanceof ResourceCommandWrapper resourceCommandWrapper) {
|
||||
ResourceCommand resourceCommand = resourceCommandWrapper.getResourceCommand();
|
||||
if (resourceCommand != null) {
|
||||
String wrapperName = innerCommand.getClass().getSimpleName();
|
||||
String commandName = resourceCommand.getClass().getSimpleName();
|
||||
if (!wrapperName.equals(commandName)) {
|
||||
throw new MismatchedCommandException(
|
||||
Ascii.toLowerCase(wrapperName), Ascii.toLowerCase(commandName));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Try the FlowProviders until we find a match. The order matters because it's possible to
|
||||
// match multiple FlowProviders and so more specific matches are tried first.
|
||||
for (FlowProvider flowProvider : FLOW_PROVIDERS) {
|
||||
@@ -279,4 +291,14 @@ public class FlowPicker {
|
||||
super("Command missing");
|
||||
}
|
||||
}
|
||||
|
||||
/** Command wrapper and inner resource command do not match. */
|
||||
static class MismatchedCommandException extends SyntaxErrorException {
|
||||
public MismatchedCommandException(String wrapperName, String commandName) {
|
||||
super(
|
||||
String.format(
|
||||
"EPP command wrapper <%s> does not match resource command <%s>",
|
||||
wrapperName, commandName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,10 @@ public class FeatureFlag extends ImmutableObject implements Buildable {
|
||||
INCLUDE_PENDING_DELETE_DATE_FOR_DOMAINS(FeatureStatus.INACTIVE),
|
||||
|
||||
/** If we're prohibiting the inclusion of the contact object URI on login. */
|
||||
PROHIBIT_CONTACT_OBJECTS_ON_LOGIN(FeatureStatus.INACTIVE);
|
||||
PROHIBIT_CONTACT_OBJECTS_ON_LOGIN(FeatureStatus.INACTIVE),
|
||||
|
||||
/** If we're prohibiting insecure algorithms as detailed by RFC 9904. */
|
||||
FORBID_INSECURE_ALGORITHMS_RFC_9904(FeatureStatus.INACTIVE);
|
||||
|
||||
private final FeatureStatus defaultStatus;
|
||||
|
||||
|
||||
@@ -118,7 +118,9 @@ public class PasswordResetRequest extends ImmutableObject implements Buildable {
|
||||
checkArgumentNotNull(getInstance().requester, "Requester must be specified");
|
||||
checkArgumentNotNull(getInstance().destinationEmail, "Destination email must be specified");
|
||||
checkArgumentNotNull(getInstance().registrarId, "Registrar ID must be specified");
|
||||
getInstance().verificationCode = UUID.randomUUID().toString();
|
||||
if (getInstance().verificationCode == null) {
|
||||
getInstance().verificationCode = UUID.randomUUID().toString();
|
||||
}
|
||||
return super.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
package google.registry.model.domain.fee;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -31,6 +30,13 @@ import java.time.Period;
|
||||
*/
|
||||
public class Fee extends BaseFee {
|
||||
|
||||
public static final ImmutableSet<String> FEE_EXTENSION_URIS =
|
||||
ImmutableSet.of(
|
||||
ServiceExtension.FEE_1_00.getUri(),
|
||||
ServiceExtension.FEE_0_12.getUri(),
|
||||
ServiceExtension.FEE_0_11.getUri(),
|
||||
ServiceExtension.FEE_0_6.getUri());
|
||||
|
||||
@Override
|
||||
public Fee clone() {
|
||||
return (Fee) super.clone();
|
||||
@@ -40,8 +46,14 @@ public class Fee extends BaseFee {
|
||||
public static Fee create(
|
||||
BigDecimal cost, FeeType type, boolean isPremium, Object... descriptionArgs) {
|
||||
checkArgumentNotNull(type, "Must specify the type of the fee");
|
||||
return createWithCustomDescription(
|
||||
cost, type, isPremium, type.renderDescription(descriptionArgs));
|
||||
checkArgumentNotNull(cost, "Cost cannot be null");
|
||||
checkArgument(cost.signum() >= 0, "Cost must be a non-negative number");
|
||||
Fee instance = new Fee();
|
||||
instance.cost = cost;
|
||||
instance.type = type;
|
||||
instance.isPremium = isPremium;
|
||||
instance.description = type.renderDescription(descriptionArgs);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** Creates a Fee for the given cost, type, and valid date range with the default description. */
|
||||
@@ -56,25 +68,6 @@ public class Fee extends BaseFee {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** Creates a Fee for the given cost and type with a custom description. */
|
||||
private static Fee createWithCustomDescription(
|
||||
BigDecimal cost, FeeType type, boolean isPremium, String description) {
|
||||
Fee instance = new Fee();
|
||||
instance.cost = checkNotNull(cost);
|
||||
checkArgument(instance.cost.signum() >= 0, "Cost must be a non-negative number");
|
||||
instance.type = checkNotNull(type);
|
||||
instance.isPremium = isPremium;
|
||||
instance.description = description;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static final ImmutableSet<String> FEE_EXTENSION_URIS =
|
||||
ImmutableSet.of(
|
||||
ServiceExtension.FEE_1_00.getUri(),
|
||||
ServiceExtension.FEE_0_12.getUri(),
|
||||
ServiceExtension.FEE_0_11.getUri(),
|
||||
ServiceExtension.FEE_0_6.getUri());
|
||||
|
||||
/** Builder for {@link Fee}. */
|
||||
public static class Builder extends Buildable.Builder<Fee> {
|
||||
|
||||
|
||||
+2
-2
@@ -63,12 +63,12 @@ public class FeeTransformResponseExtension extends ImmutableObject implements Re
|
||||
}
|
||||
|
||||
public Builder setFees(List<Fee> fees) {
|
||||
getInstance().fees = fees;
|
||||
getInstance().fees = forceEmptyToNull(nullToEmptyImmutableCopy(fees));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setCredits(List<Credit> credits) {
|
||||
getInstance().credits = forceEmptyToNull(credits);
|
||||
getInstance().credits = forceEmptyToNull(nullToEmptyImmutableCopy(credits));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -14,13 +14,12 @@
|
||||
|
||||
package google.registry.model.domain.feestdv1;
|
||||
|
||||
import static google.registry.util.CollectionUtils.forceEmptyToNull;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.domain.Period;
|
||||
import google.registry.model.domain.fee.Fee;
|
||||
import google.registry.model.domain.fee.FeeCheckResponseExtensionItem;
|
||||
import google.registry.model.domain.fee.FeeQueryCommandExtensionItem.CommandName;
|
||||
import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
|
||||
/** The version 1.0 response for a domain check on a single resource. */
|
||||
@@ -38,6 +37,7 @@ public class FeeCheckResponseExtensionItemStdV1 extends FeeCheckResponseExtensio
|
||||
* doesn't support "period".
|
||||
*/
|
||||
@Override
|
||||
@XmlTransient
|
||||
public Period getPeriod() {
|
||||
return super.getPeriod();
|
||||
}
|
||||
@@ -47,6 +47,7 @@ public class FeeCheckResponseExtensionItemStdV1 extends FeeCheckResponseExtensio
|
||||
* doesn't support "fee".
|
||||
*/
|
||||
@Override
|
||||
@XmlTransient
|
||||
public ImmutableList<Fee> getFees() {
|
||||
return super.getFees();
|
||||
}
|
||||
@@ -74,7 +75,7 @@ public class FeeCheckResponseExtensionItemStdV1 extends FeeCheckResponseExtensio
|
||||
|
||||
@Override
|
||||
public Builder setFees(ImmutableList<Fee> fees) {
|
||||
commandBuilder.setFee(forceEmptyToNull(ImmutableList.copyOf(fees)));
|
||||
commandBuilder.setFee(fees);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import google.registry.model.ImmutableObject;
|
||||
import jakarta.xml.bind.annotation.XmlAttribute;
|
||||
import jakarta.xml.bind.annotation.XmlValue;
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The launch phase of the TLD being addressed by this command.
|
||||
@@ -46,7 +47,7 @@ import java.util.Objects;
|
||||
* sets it is the one that needs to make sure the domain isn't a trademark and that the fields are
|
||||
* correct.
|
||||
*/
|
||||
public class LaunchPhase extends ImmutableObject {
|
||||
public final class LaunchPhase extends ImmutableObject {
|
||||
|
||||
/**
|
||||
* The phase during which trademark holders can submit domain registrations with trademark
|
||||
@@ -70,6 +71,9 @@ public class LaunchPhase extends ImmutableObject {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/** Private no-arg constructor required for JAXB and to enforce immutability elsewhere. */
|
||||
private LaunchPhase() {}
|
||||
|
||||
@XmlValue String phase;
|
||||
|
||||
/**
|
||||
@@ -79,6 +83,7 @@ public class LaunchPhase extends ImmutableObject {
|
||||
* <p>This is currently unused, but is retained so that incoming XMLs that include a subphase can
|
||||
* have it be reflected back.
|
||||
*/
|
||||
@Nullable
|
||||
@XmlAttribute(name = "name")
|
||||
String subphase;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.model.domain.secdns;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.UnsafeSerializable;
|
||||
import jakarta.persistence.Access;
|
||||
@@ -26,6 +27,7 @@ import jakarta.xml.bind.annotation.XmlTransient;
|
||||
import jakarta.xml.bind.annotation.XmlType;
|
||||
import jakarta.xml.bind.annotation.adapters.HexBinaryAdapter;
|
||||
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import org.xbill.DNS.DNSSEC.Algorithm;
|
||||
|
||||
/** Base class for {@link DomainDsData} and {@link DomainDsDataHistory}. */
|
||||
@MappedSuperclass
|
||||
@@ -33,6 +35,16 @@ import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
@XmlType(propOrder = {"keyTag", "algorithm", "digestType", "digest"})
|
||||
public abstract class DomainDsDataBase extends ImmutableObject implements UnsafeSerializable {
|
||||
|
||||
// A set of algorithms that we do not allow. See RFC 9904 for more details.
|
||||
public static final ImmutableSet<Integer> FORBIDDEN_ALGORITHMS =
|
||||
ImmutableSet.of(
|
||||
Algorithm.RSAMD5,
|
||||
Algorithm.RSASHA1,
|
||||
Algorithm.RSA_NSEC3_SHA1,
|
||||
Algorithm.DSA,
|
||||
Algorithm.DSA_NSEC3_SHA1,
|
||||
Algorithm.ECC_GOST);
|
||||
|
||||
@XmlTransient @Transient @Insignificant String domainRepoId;
|
||||
|
||||
/** The identifier for this particular key in the domain. */
|
||||
|
||||
@@ -49,10 +49,10 @@ public class ServiceMonitoringClient {
|
||||
tld, MONITORING_STATE_ENDPOINT, Collections.emptyMap(), Collections.emptyMap())) {
|
||||
|
||||
ResponseBody responseBody = response.body();
|
||||
if (responseBody == null) {
|
||||
if (responseBody == null || responseBody.contentLength() == 0) {
|
||||
throw new MosApiException(
|
||||
String.format(
|
||||
"MoSAPI Service Monitoring API " + "returned an empty body with status: %d",
|
||||
"MoSAPI Service Monitoring API returned an empty body with status: %d",
|
||||
response.code()));
|
||||
}
|
||||
String bodyString = responseBody.string();
|
||||
|
||||
@@ -30,7 +30,7 @@ public enum RdeResourceType {
|
||||
REGISTRAR("urn:ietf:params:xml:ns:rdeRegistrar-1.0", EnumSet.of(FULL, THIN)),
|
||||
IDN("urn:ietf:params:xml:ns:rdeIDN-1.0", EnumSet.of(FULL)),
|
||||
HEADER("urn:ietf:params:xml:ns:rdeHeader-1.0", EnumSet.of(FULL, THIN)),
|
||||
EPP_PARAMS("urn:ietf:params:xml:ns:rdeEppParams-1.0", EnumSet.of(FULL, THIN));
|
||||
EPP_PARAMS("urn:ietf:params:xml:ns:rdeEppParams-1.0", EnumSet.of(FULL));
|
||||
|
||||
private final String uri;
|
||||
private final ImmutableSet<RdeMode> modes;
|
||||
|
||||
@@ -21,10 +21,8 @@ import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import com.google.cloud.storage.BlobId;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.net.MediaType;
|
||||
@@ -41,6 +39,8 @@ import jakarta.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** Copy all registrar detail reports in a given bucket's subdirectory from GCS to Drive. */
|
||||
@Action(
|
||||
@@ -54,6 +54,9 @@ public final class CopyDetailReportsAction implements Runnable {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static final Pattern FILENAME_PATTERN =
|
||||
Pattern.compile("^invoice_details_[0-9]{4}-[0-9]{2}_(.+)_.+\\.csv$");
|
||||
|
||||
private final String billingBucket;
|
||||
private final String invoiceDirectoryPrefix;
|
||||
private final DriveConnection driveConnection;
|
||||
@@ -101,8 +104,13 @@ public final class CopyDetailReportsAction implements Runnable {
|
||||
new ImmutableMultimap.Builder<>();
|
||||
for (String detailReportName : detailReportObjectNames) {
|
||||
// The standard report format is "invoice_details_yyyy-MM_registrarId_tld.csv
|
||||
// TODO(larryruili): Determine a safer way of enforcing this.
|
||||
String registrarId = Iterables.get(Splitter.on('_').split(detailReportName), 3);
|
||||
Matcher matcher = FILENAME_PATTERN.matcher(detailReportName);
|
||||
if (!matcher.matches()) {
|
||||
logger.atWarning().log(
|
||||
"Detail report filename '%s' does not match the expected pattern.", detailReportName);
|
||||
continue;
|
||||
}
|
||||
String registrarId = matcher.group(1);
|
||||
Optional<Registrar> registrar = Registrar.loadByRegistrarId(registrarId);
|
||||
if (registrar.isEmpty()) {
|
||||
logger.atWarning().log(
|
||||
|
||||
@@ -18,8 +18,8 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.net.HttpHeaders.CONTENT_DISPOSITION;
|
||||
import static com.google.common.net.HttpHeaders.X_CONTENT_TYPE_OPTIONS;
|
||||
import static com.google.common.net.MediaType.JSON_UTF_8;
|
||||
import static org.json.simple.JSONValue.toJSONString;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
@@ -31,10 +31,12 @@ public class JsonResponse {
|
||||
public static final String JSON_SAFETY_PREFIX = ")]}'\n";
|
||||
|
||||
protected final Response response;
|
||||
protected final Gson gson;
|
||||
|
||||
@Inject
|
||||
public JsonResponse(Response rsp) {
|
||||
public JsonResponse(Response rsp, Gson gson) {
|
||||
this.response = rsp;
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,7 +57,7 @@ public class JsonResponse {
|
||||
// response, even if all else fails. It's basically another anti-sniffing mechanism in the sense
|
||||
// that if you hit this url directly, it would try to download the file instead of showing it.
|
||||
response.setHeader(CONTENT_DISPOSITION, "attachment");
|
||||
response.setPayload(JSON_SAFETY_PREFIX + toJSONString(checkNotNull(responseMap)));
|
||||
response.setPayload(JSON_SAFETY_PREFIX + gson.toJson(checkNotNull(responseMap)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.request;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.net.MediaType.JSON_UTF_8;
|
||||
import static google.registry.dns.PublishDnsUpdatesAction.CLOUD_TASKS_RETRY_HEADER;
|
||||
import static google.registry.model.tld.Tlds.assertTldExists;
|
||||
@@ -28,7 +29,6 @@ import static google.registry.request.RequestParameters.extractSetOfParameters;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.VerifyException;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.io.ByteStreams;
|
||||
@@ -36,6 +36,8 @@ import com.google.common.io.CharStreams;
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.protobuf.ByteString;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
@@ -50,8 +52,6 @@ import jakarta.servlet.http.HttpSession;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
/** Dagger module for servlets. */
|
||||
@Module
|
||||
@@ -202,18 +202,16 @@ public final class RequestModule {
|
||||
|
||||
@Provides
|
||||
@JsonPayload
|
||||
@SuppressWarnings("unchecked")
|
||||
static Map<String, Object> provideJsonPayload(
|
||||
@Header("Content-Type") MediaType contentType, @Payload String payload) {
|
||||
@Header("Content-Type") MediaType contentType, @Payload String payload, Gson gson) {
|
||||
if (!JSON_UTF_8.is(contentType.withCharset(UTF_8))) {
|
||||
throw new UnsupportedMediaTypeException(
|
||||
String.format("Expected %s Content-Type", JSON_UTF_8.withoutParameters()));
|
||||
}
|
||||
try {
|
||||
return (Map<String, Object>) JSONValue.parseWithException(payload);
|
||||
} catch (ParseException e) {
|
||||
throw new BadRequestException(
|
||||
"Malformed JSON", new VerifyException("Malformed JSON:\n" + payload, e));
|
||||
return checkNotNull(gson.fromJson(payload, new TypeToken<>() {}));
|
||||
} catch (JsonSyntaxException | NullPointerException e) {
|
||||
throw new BadRequestException("Malformed JSON:\n" + payload);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ import jakarta.inject.Qualifier;
|
||||
import jakarta.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@@ -88,8 +89,8 @@ public class AuthModule {
|
||||
TokenVerifier provideIapTokenVerifier(
|
||||
@Config("projectIdNumber") long projectIdNumber,
|
||||
@Named("backendServiceIdMap") Supplier<ImmutableMap<String, Long>> backendServiceIdMap) {
|
||||
com.google.auth.oauth2.TokenVerifier.Builder tokenVerifierBuilder =
|
||||
com.google.auth.oauth2.TokenVerifier.newBuilder().setIssuer(IAP_ISSUER_URL);
|
||||
ConcurrentHashMap<String, com.google.auth.oauth2.TokenVerifier> tokenVerifiers =
|
||||
new ConcurrentHashMap<>();
|
||||
return (String service, String token) -> {
|
||||
Long backendServiceId = backendServiceIdMap.get().get(service);
|
||||
checkNotNull(
|
||||
@@ -98,7 +99,15 @@ public class AuthModule {
|
||||
service,
|
||||
backendServiceIdMap);
|
||||
String audience = String.format(IAP_AUDIENCE_FORMAT, projectIdNumber, backendServiceId);
|
||||
return tokenVerifierBuilder.setAudience(audience).build().verify(token);
|
||||
com.google.auth.oauth2.TokenVerifier verifier =
|
||||
tokenVerifiers.computeIfAbsent(
|
||||
audience,
|
||||
aud ->
|
||||
com.google.auth.oauth2.TokenVerifier.newBuilder()
|
||||
.setIssuer(IAP_ISSUER_URL)
|
||||
.setAudience(aud)
|
||||
.build());
|
||||
return verifier.verify(token);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.net.HttpHeaders.CONTENT_DISPOSITION;
|
||||
import static com.google.common.net.HttpHeaders.X_CONTENT_TYPE_OPTIONS;
|
||||
import static com.google.common.net.MediaType.JSON_UTF_8;
|
||||
import static org.json.simple.JSONValue.writeJSONString;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
@@ -29,8 +32,6 @@ import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
/**
|
||||
* Helper class for servlets that read or write JSON.
|
||||
@@ -41,6 +42,8 @@ public final class JsonHttp {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static final Gson GSON = GsonUtils.provideGson();
|
||||
|
||||
/** String prefixed to all JSON-like responses. */
|
||||
public static final String JSON_SAFETY_PREFIX = ")]}'\n";
|
||||
|
||||
@@ -51,7 +54,6 @@ public final class JsonHttp {
|
||||
* @throws IOException if we failed to read from {@code req}.
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, ?> read(HttpServletRequest req) throws IOException {
|
||||
if (!"POST".equals(req.getMethod())
|
||||
&& !"PUT".equals(req.getMethod())) {
|
||||
@@ -64,8 +66,8 @@ public final class JsonHttp {
|
||||
}
|
||||
try (Reader jsonReader = req.getReader()) {
|
||||
try {
|
||||
return checkNotNull((Map<String, ?>) JSONValue.parseWithException(jsonReader));
|
||||
} catch (ParseException | NullPointerException | ClassCastException e) {
|
||||
return checkNotNull(GSON.fromJson(jsonReader, new TypeToken<>() {}));
|
||||
} catch (JsonSyntaxException | NullPointerException | ClassCastException e) {
|
||||
logger.atWarning().withCause(e).log("Malformed JSON.");
|
||||
return null;
|
||||
}
|
||||
@@ -88,7 +90,7 @@ public final class JsonHttp {
|
||||
rsp.setHeader(CONTENT_DISPOSITION, "attachment");
|
||||
try (Writer writer = rsp.getWriter()) {
|
||||
writer.write(JSON_SAFETY_PREFIX);
|
||||
writeJSONString(jsonObject, writer);
|
||||
GSON.toJson(jsonObject, writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.google.common.hash.Hashing;
|
||||
import google.registry.model.server.ServerSecret;
|
||||
import google.registry.util.Clock;
|
||||
import jakarta.inject.Inject;
|
||||
import java.security.MessageDigest;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
@@ -102,7 +103,7 @@ public final class XsrfTokenManager {
|
||||
}
|
||||
// Reconstruct the token to verify validity.
|
||||
String reconstructedToken = encodeToken(ServerSecret.get().asBytes(), email, timestampMillis);
|
||||
if (!token.equals(reconstructedToken)) {
|
||||
if (!MessageDigest.isEqual(token.getBytes(UTF_8), reconstructedToken.getBytes(UTF_8))) {
|
||||
logger.atWarning().log(
|
||||
"Reconstructed XSRF mismatch (got != expected): %s != %s", token, reconstructedToken);
|
||||
return false;
|
||||
|
||||
@@ -29,21 +29,26 @@ import java.util.Optional;
|
||||
* https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml
|
||||
*/
|
||||
public enum DigestType {
|
||||
SHA1(1, 20),
|
||||
SHA256(2, 32),
|
||||
// Algorithm number 1 is SHA-1 and will be is deliberately NOT SUPPORTED.
|
||||
// RFC 9904 specifies that this algorithm MUST NOT be used for DNSSEC delegations.
|
||||
// This prohibition is gated behind a feature flag.
|
||||
SHA1(1, 20, false),
|
||||
SHA256(2, 32, true),
|
||||
// Algorithm number 3 is GOST R 34.11-94 and is deliberately NOT SUPPORTED.
|
||||
// This algorithm was reviewed by ise-crypto and deemed academically broken (b/207029800).
|
||||
// In addition, RFC 8624 specifies that this algorithm MUST NOT be used for DNSSEC delegations.
|
||||
// TODO(sarhabot@): Add note in Cloud DNS code to notify the Registry of any new changes to
|
||||
// supported digest types.
|
||||
SHA384(4, 48);
|
||||
SHA384(4, 48, true);
|
||||
|
||||
private final int wireValue;
|
||||
private final int bytes;
|
||||
private final boolean allowedInRfc9904;
|
||||
|
||||
DigestType(int wireValue, int bytes) {
|
||||
DigestType(int wireValue, int bytes, boolean allowedInRfc9904) {
|
||||
this.wireValue = wireValue;
|
||||
this.bytes = bytes;
|
||||
this.allowedInRfc9904 = allowedInRfc9904;
|
||||
}
|
||||
|
||||
private static final ImmutableMap<Integer, DigestType> WIRE_VALUE_TO_DIGEST_TYPE =
|
||||
@@ -63,4 +68,9 @@ public enum DigestType {
|
||||
public int getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/** Whether this digest type is supported as of RFC 9904. */
|
||||
public boolean isAllowedInRfc9904() {
|
||||
return allowedInRfc9904;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
||||
|
||||
import com.beust.jcommander.IStringConverter;
|
||||
@@ -46,7 +47,7 @@ record DsRecord(int keyTag, int alg, int digestType, String digest) {
|
||||
String.format("DS record has an invalid digest length: %s", digest));
|
||||
}
|
||||
|
||||
if (!DomainFlowUtils.validateAlgorithm(alg)) {
|
||||
if (tm().reTransact(() -> DomainFlowUtils.algorithmIsInvalid(alg))) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("DS record uses an unrecognized algorithm: %d", alg));
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.persistence.transaction.QueryComposer.Comparator;
|
||||
@@ -38,7 +39,6 @@ import java.nio.file.Paths;
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
/** Command to generate a report of all DNS data. */
|
||||
@Parameters(separators = " =", commandDescription = "Generate report of all DNS data in a TLD.")
|
||||
@@ -57,6 +57,7 @@ final class GenerateDnsReportCommand implements Command {
|
||||
private Path output = Paths.get("/dev/stdout");
|
||||
|
||||
@Inject Clock clock;
|
||||
@Inject Gson gson;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
@@ -144,7 +145,7 @@ final class GenerateDnsReportCommand implements Command {
|
||||
} else {
|
||||
result.append(",\n");
|
||||
}
|
||||
result.append(JSONValue.toJSONString(map));
|
||||
result.append(gson.toJson(map));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package google.registry.tools;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.ToNumberPolicy;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.TypeAdapterFactory;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
@@ -82,6 +83,7 @@ public class GsonUtils {
|
||||
.registerTypeAdapter(Serializable.class, new SerializableJsonTypeAdapter())
|
||||
.registerTypeAdapterFactory(new ClassProcessingTypeAdapterFactory())
|
||||
.registerTypeAdapterFactory(new GsonPostProcessableTypeAdapterFactory())
|
||||
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
|
||||
.excludeFieldsWithoutExposeAnnotation()
|
||||
.create();
|
||||
}
|
||||
|
||||
@@ -23,10 +23,13 @@ import com.beust.jcommander.Parameter;
|
||||
import com.google.common.base.VerifyException;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
/**
|
||||
* Abstract base class for commands that list objects by calling a server task.
|
||||
@@ -35,6 +38,8 @@ import org.json.simple.JSONValue;
|
||||
*/
|
||||
abstract class ListObjectsCommand implements CommandWithConnection {
|
||||
|
||||
private static final Gson GSON = GsonUtils.provideGson();
|
||||
|
||||
@Nullable
|
||||
@Parameter(
|
||||
names = {"-f", "--fields"},
|
||||
@@ -87,14 +92,13 @@ abstract class ListObjectsCommand implements CommandWithConnection {
|
||||
connection.sendPostRequest(
|
||||
getCommandPath(), params.build(), MediaType.PLAIN_TEXT_UTF_8, new byte[0]);
|
||||
// Parse the returned JSON and make sure it's a map.
|
||||
Object obj = JSONValue.parse(response.substring(JSON_SAFETY_PREFIX.length()));
|
||||
if (!(obj instanceof Map<?, ?>)) {
|
||||
JsonElement element = JsonParser.parseString(response.substring(JSON_SAFETY_PREFIX.length()));
|
||||
if (!element.isJsonObject()) {
|
||||
throw new VerifyException("Server returned unexpected JSON: " + response);
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> responseMap = (Map<String, Object>) obj;
|
||||
Map<String, Object> responseMap = GSON.fromJson(element, new TypeToken<>() {});
|
||||
// Get the status.
|
||||
obj = responseMap.get("status");
|
||||
Object obj = responseMap.get("status");
|
||||
if (obj == null) {
|
||||
throw new VerifyException("Server returned no status");
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.request.Action.Service;
|
||||
import jakarta.inject.Inject;
|
||||
@@ -42,7 +44,6 @@ import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
import org.json.simple.JSONValue;
|
||||
|
||||
/**
|
||||
* An HTTP connection to a service.
|
||||
@@ -55,23 +56,25 @@ public class ServiceConnection {
|
||||
private final Service service;
|
||||
private final boolean useCanary;
|
||||
private final HttpRequestFactory requestFactory;
|
||||
private final Gson gson;
|
||||
|
||||
@Inject
|
||||
ServiceConnection(
|
||||
@Config("useCanary") boolean useCanary,
|
||||
HttpRequestFactory requestFactory) {
|
||||
this(Service.BACKEND, requestFactory, useCanary);
|
||||
@Config("useCanary") boolean useCanary, HttpRequestFactory requestFactory, Gson gson) {
|
||||
this(Service.BACKEND, requestFactory, useCanary, gson);
|
||||
}
|
||||
|
||||
private ServiceConnection(Service service, HttpRequestFactory requestFactory, boolean useCanary) {
|
||||
private ServiceConnection(
|
||||
Service service, HttpRequestFactory requestFactory, boolean useCanary, Gson gson) {
|
||||
this.service = service;
|
||||
this.requestFactory = requestFactory;
|
||||
this.useCanary = useCanary;
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
/** Returns a copy of this connection that talks to a different service endpoint. */
|
||||
public ServiceConnection withService(Service service, boolean useCanary) {
|
||||
return new ServiceConnection(service, requestFactory, useCanary);
|
||||
return new ServiceConnection(service, requestFactory, useCanary, gson);
|
||||
}
|
||||
|
||||
/** Returns the HTML from the connection error stream, if any, otherwise the empty string. */
|
||||
@@ -99,7 +102,7 @@ public class ServiceConnection {
|
||||
request.setFollowRedirects(false);
|
||||
request.setThrowExceptionOnExecuteError(false);
|
||||
request.setUnsuccessfulResponseHandler(
|
||||
(request1, response, supportsRetry) -> {
|
||||
(request1, response, _) -> {
|
||||
String error = getErrorHtmlAsString(response);
|
||||
throw new IOException(
|
||||
String.format(
|
||||
@@ -137,14 +140,10 @@ public class ServiceConnection {
|
||||
return internalSend(endpoint, params, MediaType.PLAIN_TEXT_UTF_8, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> sendJson(String endpoint, Map<String, ?> object) throws IOException {
|
||||
String response =
|
||||
sendPostRequest(
|
||||
endpoint,
|
||||
ImmutableMap.of(),
|
||||
JSON_UTF_8,
|
||||
JSONValue.toJSONString(object).getBytes(UTF_8));
|
||||
return (Map<String, Object>) JSONValue.parse(response.substring(JSON_SAFETY_PREFIX.length()));
|
||||
endpoint, ImmutableMap.of(), JSON_UTF_8, gson.toJson(object).getBytes(UTF_8));
|
||||
return gson.fromJson(response.substring(JSON_SAFETY_PREFIX.length()), new TypeToken<>() {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,8 @@ public abstract class ConsoleApiAction implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkPermission(User user, String registrarId, ConsolePermission permission) {
|
||||
protected static void checkPermission(
|
||||
User user, String registrarId, ConsolePermission permission) {
|
||||
if (!user.getUserRoles().hasPermission(registrarId, permission)) {
|
||||
throw new ConsolePermissionForbiddenException(
|
||||
String.format(
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.flows.EppException.AuthenticationErrorException;
|
||||
import google.registry.flows.PasswordOnlyTransportCredentials;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.ConsoleUpdateHistory;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
@@ -84,6 +85,8 @@ public class ConsoleEppPasswordAction extends ConsoleApiAction {
|
||||
eppRequestBody.newPassword().equals(eppRequestBody.newPasswordRepeat()),
|
||||
"New password fields don't match");
|
||||
|
||||
checkPermission(user, eppRequestBody.registrarId(), ConsolePermission.CONFIGURE_EPP_CONNECTION);
|
||||
|
||||
Registrar registrar;
|
||||
try {
|
||||
registrar = registrarAccessor.getRegistrar(eppRequestBody.registrarId());
|
||||
|
||||
@@ -62,17 +62,20 @@ public class ConsoleHistoryDataAction extends ConsoleApiAction {
|
||||
private final Optional<String> consoleUserEmail;
|
||||
|
||||
private final String supportEmail;
|
||||
private final int historyQueryLimit;
|
||||
|
||||
@Inject
|
||||
public ConsoleHistoryDataAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
@Config("supportEmail") String supportEmail,
|
||||
@Config("consoleHistoryQueryLimit") int historyQueryLimit,
|
||||
@Parameter("registrarId") String registrarId,
|
||||
@Parameter("consoleUserEmail") Optional<String> consoleUserEmail) {
|
||||
super(consoleApiParams);
|
||||
this.registrarId = registrarId;
|
||||
this.consoleUserEmail = consoleUserEmail;
|
||||
this.supportEmail = supportEmail;
|
||||
this.historyQueryLimit = historyQueryLimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,6 +120,7 @@ public class ConsoleHistoryDataAction extends ConsoleApiAction {
|
||||
.createNativeQuery(SQL_REGISTRAR_HISTORY, ConsoleUpdateHistory.class)
|
||||
.setParameter("registrarId", registrarId)
|
||||
.setHint("org.hibernate.fetchSize", 1000)
|
||||
.setMaxResults(historyQueryLimit)
|
||||
.getResultList());
|
||||
|
||||
List<ConsoleUpdateHistory> formattedHistoryList =
|
||||
|
||||
+18
-7
@@ -86,7 +86,7 @@ public class PasswordResetRequestAction extends ConsoleApiAction {
|
||||
"Must provide registry lock email to reset");
|
||||
requiredPermission = ConsolePermission.MANAGE_USERS;
|
||||
destinationEmail = passwordResetRequestData.registryLockEmail;
|
||||
checkUserExistsWithRegistryLockEmail(destinationEmail);
|
||||
checkUserExistsWithRegistryLockEmail(destinationEmail, registrarId);
|
||||
emailSubject = "Registry lock password reset request";
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unknown type " + type);
|
||||
@@ -121,12 +121,23 @@ public class PasswordResetRequestAction extends ConsoleApiAction {
|
||||
.sendEmail(EmailMessage.create(emailSubject, body, destinationAddress));
|
||||
}
|
||||
|
||||
static User checkUserExistsWithRegistryLockEmail(String destinationEmail) {
|
||||
return tm().createQueryComposer(User.class)
|
||||
.where("registryLockEmailAddress", QueryComposer.Comparator.EQ, destinationEmail)
|
||||
.first()
|
||||
.orElseThrow(
|
||||
() -> new IllegalArgumentException("Unknown user with lock email " + destinationEmail));
|
||||
static User checkUserExistsWithRegistryLockEmail(String destinationEmail, String registrarId) {
|
||||
User targetUser =
|
||||
tm().createQueryComposer(User.class)
|
||||
.where("registryLockEmailAddress", QueryComposer.Comparator.EQ, destinationEmail)
|
||||
.first()
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalArgumentException(
|
||||
"Unknown user with lock email " + destinationEmail));
|
||||
|
||||
// Prevent IDOR: Ensure the resolved user has the right permission
|
||||
checkArgument(
|
||||
targetUser.getUserRoles().hasPermission(registrarId, ConsolePermission.REGISTRY_LOCK),
|
||||
"User %s does not have permission REGISTRY_LOCK on registrar %s",
|
||||
targetUser.getEmailAddress(),
|
||||
registrarId);
|
||||
return targetUser;
|
||||
}
|
||||
|
||||
private String getAdminPocEmail(String registrarId) {
|
||||
|
||||
+12
-2
@@ -98,7 +98,9 @@ public class PasswordResetVerifyAction extends ConsoleApiAction {
|
||||
}
|
||||
|
||||
private void handleRegistryLockPasswordReset(PasswordResetRequest request) {
|
||||
User affectedUser = checkUserExistsWithRegistryLockEmail(request.getDestinationEmail());
|
||||
User affectedUser =
|
||||
checkUserExistsWithRegistryLockEmail(
|
||||
request.getDestinationEmail(), request.getRegistrarId());
|
||||
tm().put(
|
||||
affectedUser
|
||||
.asBuilder()
|
||||
@@ -119,7 +121,15 @@ public class PasswordResetVerifyAction extends ConsoleApiAction {
|
||||
ConsolePermission requiredVerifyPermission =
|
||||
switch (request.getType()) {
|
||||
case EPP -> ConsolePermission.MANAGE_USERS;
|
||||
case REGISTRY_LOCK -> ConsolePermission.REGISTRY_LOCK;
|
||||
case REGISTRY_LOCK -> {
|
||||
checkArgument(
|
||||
user.getRegistryLockEmailAddress()
|
||||
.map(address -> address.equals(request.getDestinationEmail()))
|
||||
.orElse(false),
|
||||
"User %s has the wrong registry lock email address",
|
||||
user.getEmailAddress());
|
||||
yield ConsolePermission.REGISTRY_LOCK;
|
||||
}
|
||||
};
|
||||
checkPermission(user, request.getRegistrarId(), requiredVerifyPermission);
|
||||
if (plusHours(request.getRequestTime(), 1).isBefore(tm().getTxTime())) {
|
||||
|
||||
+12
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.ui.server.console.domains;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
@@ -22,6 +23,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.flows.EppController;
|
||||
import google.registry.flows.EppRequestSource;
|
||||
import google.registry.flows.PasswordOnlyTransportCredentials;
|
||||
@@ -64,11 +66,13 @@ public class ConsoleBulkDomainAction extends ConsoleApiAction {
|
||||
private final String registrarId;
|
||||
private final String bulkDomainAction;
|
||||
private final Optional<JsonElement> optionalJsonPayload;
|
||||
private final int bulkDomainActionLimit;
|
||||
|
||||
@Inject
|
||||
public ConsoleBulkDomainAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
EppController eppController,
|
||||
@Config("consoleBulkDomainActionLimit") int bulkDomainActionLimit,
|
||||
@Parameter("registrarId") String registrarId,
|
||||
@Parameter("bulkDomainAction") String bulkDomainAction,
|
||||
@OptionalJsonPayload Optional<JsonElement> optionalJsonPayload) {
|
||||
@@ -77,6 +81,7 @@ public class ConsoleBulkDomainAction extends ConsoleApiAction {
|
||||
this.registrarId = registrarId;
|
||||
this.bulkDomainAction = bulkDomainAction;
|
||||
this.optionalJsonPayload = optionalJsonPayload;
|
||||
this.bulkDomainActionLimit = bulkDomainActionLimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,6 +90,13 @@ public class ConsoleBulkDomainAction extends ConsoleApiAction {
|
||||
optionalJsonPayload.orElseThrow(
|
||||
() -> new IllegalArgumentException("Bulk action payload must be present"));
|
||||
BulkDomainList domainList = consoleApiParams.gson().fromJson(jsonPayload, BulkDomainList.class);
|
||||
checkArgument(
|
||||
domainList.domainList != null && !domainList.domainList.isEmpty(),
|
||||
"Domain list cannot be empty");
|
||||
checkArgument(
|
||||
domainList.domainList.size() <= bulkDomainActionLimit,
|
||||
"Cannot process more than %s domains in a single bulk action",
|
||||
bulkDomainActionLimit);
|
||||
ConsoleDomainActionType actionType =
|
||||
ConsoleDomainActionType.parseActionType(bulkDomainAction, jsonPayload);
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.LogsSubject.assertAboutLogs;
|
||||
import static google.registry.util.DateTimeUtils.START_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.minusDays;
|
||||
import static google.registry.util.NetworkUtils.pickUnusedPort;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.util.concurrent.Executors.newSingleThreadExecutor;
|
||||
import static org.mockito.Mockito.times;
|
||||
@@ -168,7 +167,7 @@ public class UploadBsaUnavailableDomainsActionTest {
|
||||
private TestServer startTestServer() throws Exception {
|
||||
TestServer testServer =
|
||||
new TestServer(
|
||||
HostAndPort.fromParts(InetAddress.getLocalHost().getHostAddress(), pickUnusedPort()),
|
||||
HostAndPort.fromParts(InetAddress.getLocalHost().getHostAddress(), 0),
|
||||
ImmutableMap.of(),
|
||||
ImmutableList.of(Route.route("/upload", Servlet.class)));
|
||||
testServer.start();
|
||||
|
||||
@@ -19,6 +19,7 @@ import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableO
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveSubordinateHost;
|
||||
import static google.registry.testing.DatabaseHelper.persistDeletedDomain;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -67,7 +68,8 @@ public class SimplifiedJedisClientTest {
|
||||
|
||||
@Test
|
||||
void testClient_roundTrip_host() {
|
||||
Host host = persistActiveHost("ns1.example.tld");
|
||||
Domain domain = persistActiveDomain("example.tld");
|
||||
Host host = persistActiveSubordinateHost("ns1.example.tld", domain);
|
||||
SimplifiedJedisClient client = createJedisClient();
|
||||
client.set(new SimplifiedJedisClient.JedisResource<>("repoId1", host));
|
||||
assertThat(client.get(Host.class, "repoId1")).hasValue(host);
|
||||
|
||||
@@ -21,8 +21,8 @@ import static google.registry.model.common.FeatureFlag.FeatureStatus.INACTIVE;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistDeletedDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistFeatureFlag;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.START_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.plusDays;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
@@ -35,10 +35,8 @@ import com.google.cloud.storage.BlobId;
|
||||
import com.google.cloud.storage.StorageException;
|
||||
import com.google.cloud.storage.contrib.nio.testing.LocalStorageHelper;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.gcs.GcsUtils;
|
||||
import google.registry.model.common.FeatureFlag;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
@@ -80,7 +78,7 @@ class ExportDomainListsActionTest {
|
||||
action.gcsUtils = gcsUtils;
|
||||
action.clock = clock;
|
||||
action.driveConnection = driveConnection;
|
||||
persistFeatureFlag(INACTIVE);
|
||||
persistFeatureFlag(INCLUDE_PENDING_DELETE_DATE_FOR_DOMAINS, INACTIVE);
|
||||
}
|
||||
|
||||
private void verifyExportedToDrive(String folderId, String filename, String domains)
|
||||
@@ -110,7 +108,7 @@ class ExportDomainListsActionTest {
|
||||
|
||||
@Test
|
||||
void test_outputsOnlyActiveDomains_csv() throws Exception {
|
||||
persistFeatureFlag(ACTIVE);
|
||||
persistFeatureFlag(INCLUDE_PENDING_DELETE_DATE_FOR_DOMAINS, ACTIVE);
|
||||
persistActiveDomain("onetwo.tld");
|
||||
persistActiveDomain("rudnitzky.tld");
|
||||
persistDeletedDomain("mortuary.tld", Instant.parse("2001-03-14T10:11:12Z"));
|
||||
@@ -144,7 +142,7 @@ class ExportDomainListsActionTest {
|
||||
|
||||
@Test
|
||||
void test_outputsOnlyDomainsOnRealTlds_csv() throws Exception {
|
||||
persistFeatureFlag(ACTIVE);
|
||||
persistFeatureFlag(INCLUDE_PENDING_DELETE_DATE_FOR_DOMAINS, ACTIVE);
|
||||
persistActiveDomain("onetwo.tld");
|
||||
persistActiveDomain("rudnitzky.tld");
|
||||
persistActiveDomain("wontgo.testtld");
|
||||
@@ -164,7 +162,7 @@ class ExportDomainListsActionTest {
|
||||
|
||||
@Test
|
||||
void test_outputIncludesDeletionTimes_forPendingDeletes_notRdemption() throws Exception {
|
||||
persistFeatureFlag(ACTIVE);
|
||||
persistFeatureFlag(INCLUDE_PENDING_DELETE_DATE_FOR_DOMAINS, ACTIVE);
|
||||
// Domains pending delete (meaning the 5 day period, not counting the 30 day redemption period)
|
||||
// should include their pending deletion date
|
||||
persistActiveDomain("active.tld");
|
||||
@@ -227,7 +225,7 @@ class ExportDomainListsActionTest {
|
||||
|
||||
@Test
|
||||
void test_outputsDomainsFromDifferentTldsToMultipleFiles_csv() throws Exception {
|
||||
persistFeatureFlag(ACTIVE);
|
||||
persistFeatureFlag(INCLUDE_PENDING_DELETE_DATE_FOR_DOMAINS, ACTIVE);
|
||||
createTld("tldtwo");
|
||||
persistResource(Tld.get("tldtwo").asBuilder().setDriveFolderId("hooray").build());
|
||||
|
||||
@@ -255,13 +253,4 @@ class ExportDomainListsActionTest {
|
||||
// tldthree does not have a drive id, so no export to drive is performed.
|
||||
verifyNoMoreInteractions(driveConnection);
|
||||
}
|
||||
|
||||
private void persistFeatureFlag(FeatureFlag.FeatureStatus status) {
|
||||
persistResource(
|
||||
new FeatureFlag()
|
||||
.asBuilder()
|
||||
.setFeatureName(INCLUDE_PENDING_DELETE_DATE_FOR_DOMAINS)
|
||||
.setStatusMap(ImmutableSortedMap.of(START_INSTANT, status))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.START_INSTANT;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import google.registry.bsa.persistence.BsaTestingUtils;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.monitoring.whitebox.CheckApiMetric;
|
||||
@@ -39,10 +40,10 @@ import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -83,9 +84,9 @@ class CheckApiActionTest {
|
||||
.build());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<String, Object> getCheckResponse(String domain) {
|
||||
CheckApiAction action = new CheckApiAction();
|
||||
action.gson = GsonUtils.provideGson();
|
||||
action.domain = domain;
|
||||
action.response = new FakeResponse();
|
||||
action.metricBuilder = CheckApiMetric.builder(fakeClock);
|
||||
@@ -94,7 +95,8 @@ class CheckApiActionTest {
|
||||
endTime = fakeClock.now();
|
||||
|
||||
action.run();
|
||||
return (Map<String, Object>) JSONValue.parse(((FakeResponse) action.response).getPayload());
|
||||
return action.gson.fromJson(
|
||||
((FakeResponse) action.response).getPayload(), new TypeToken<>() {});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -31,6 +31,8 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.testing.TestLogHandler;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import google.registry.flows.EppException.UnimplementedExtensionException;
|
||||
import google.registry.flows.EppTestComponent.FakeServerTridProvider;
|
||||
import google.registry.flows.FlowModule.EppExceptionInProviderException;
|
||||
@@ -43,6 +45,7 @@ import google.registry.monitoring.whitebox.EppMetric;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import google.registry.util.Clock;
|
||||
import google.registry.xml.ValidationMode;
|
||||
import java.time.Instant;
|
||||
@@ -50,7 +53,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -82,6 +84,7 @@ class EppControllerTest {
|
||||
@Mock Result result;
|
||||
|
||||
private static final Instant START_TIME = Instant.parse("2016-09-01T00:00:00Z");
|
||||
private static final Gson GSON = GsonUtils.provideGson();
|
||||
|
||||
private final Clock clock = new FakeClock(START_TIME);
|
||||
private final TestLogHandler logHandler = new TestLogHandler();
|
||||
@@ -110,6 +113,7 @@ class EppControllerTest {
|
||||
when(result.getCode()).thenReturn(Code.SUCCESS_WITH_NO_MESSAGES);
|
||||
|
||||
eppController = new EppController();
|
||||
eppController.gson = GSON;
|
||||
eppController.eppMetricBuilder = EppMetric.builderForRequest(clock);
|
||||
when(flowRunner.run(eppController.eppMetricBuilder)).thenReturn(eppOutput);
|
||||
eppController.flowComponentBuilder = flowComponentBuilder;
|
||||
@@ -247,8 +251,7 @@ class EppControllerTest {
|
||||
assertThat(logRecord.getThrown()).isInstanceOf(IllegalStateException.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Map<String, Object> parseJsonMap(String json) throws Exception {
|
||||
return (Map<String, Object>) JSONValue.parseWithException(json);
|
||||
return GSON.fromJson(json, new TypeToken<>() {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import google.registry.flows.custom.TestCustomLogicFactory;
|
||||
import google.registry.flows.domain.DomainDeletionTimeCache;
|
||||
import google.registry.flows.domain.DomainFlowTmchUtils;
|
||||
import google.registry.monitoring.whitebox.EppMetric;
|
||||
import google.registry.request.Modules.GsonModule;
|
||||
import google.registry.request.RequestScope;
|
||||
import google.registry.request.lock.LockHandler;
|
||||
import google.registry.testing.CloudTasksHelper;
|
||||
@@ -42,7 +43,8 @@ import jakarta.inject.Singleton;
|
||||
|
||||
/** Dagger component for running EPP tests. */
|
||||
@Singleton
|
||||
@Component(modules = {ConfigModule.class, EppTestComponent.FakesAndMocksModule.class})
|
||||
@Component(
|
||||
modules = {ConfigModule.class, GsonModule.class, EppTestComponent.FakesAndMocksModule.class})
|
||||
public interface EppTestComponent {
|
||||
|
||||
RequestComponent startRequest();
|
||||
|
||||
@@ -22,22 +22,26 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.testing.TestLogHandler;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import google.registry.flows.annotations.ReportingSpec;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import google.registry.model.eppoutput.EppOutput.ResponseOrGreeting;
|
||||
import google.registry.model.eppoutput.EppResponse;
|
||||
import google.registry.model.reporting.IcannReportingTypes.ActivityReportField;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import google.registry.util.JdkLoggerConfig;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link FlowReporter}. */
|
||||
class FlowReporterTest {
|
||||
|
||||
private static final Gson GSON = GsonUtils.provideGson();
|
||||
|
||||
static class TestCommandFlow implements Flow {
|
||||
@Override
|
||||
public ResponseOrGreeting run() {
|
||||
@@ -60,6 +64,7 @@ class FlowReporterTest {
|
||||
void beforeEach() {
|
||||
JdkLoggerConfig.getConfig(FlowReporter.class).addHandler(handler);
|
||||
flowReporter.trid = Trid.create("client-123", "server-456");
|
||||
flowReporter.gson = GSON;
|
||||
flowReporter.registrarId = "TheRegistrar";
|
||||
flowReporter.inputXmlBytes = "<xml/>".getBytes(UTF_8);
|
||||
flowReporter.flowClass = TestCommandFlow.class;
|
||||
@@ -205,8 +210,7 @@ class FlowReporterTest {
|
||||
assertThat(json).containsEntry("tlds", ImmutableList.of());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Map<String, Object> parseJsonMap(String json) throws Exception {
|
||||
return (Map<String, Object>) JSONValue.parseWithException(json);
|
||||
return GSON.fromJson(json, new TypeToken<>() {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.testing.TestLogHandler;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.EppResource;
|
||||
import google.registry.model.ForeignKeyUtils;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
@@ -34,13 +35,13 @@ import google.registry.model.tmch.ClaimsList;
|
||||
import google.registry.model.tmch.ClaimsListDao;
|
||||
import google.registry.testing.DatabaseHelper;
|
||||
import google.registry.testing.TestCacheExtension;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import google.registry.util.JdkLoggerConfig;
|
||||
import google.registry.util.TypeUtils.TypeInstantiator;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.logging.Level;
|
||||
import javax.annotation.Nullable;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
@@ -53,6 +54,8 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
public abstract class ResourceFlowTestCase<F extends Flow, R extends EppResource>
|
||||
extends FlowTestCase<F> {
|
||||
|
||||
private static final Gson GSON = GsonUtils.provideGson();
|
||||
|
||||
protected final TestLogHandler logHandler = new TestLogHandler();
|
||||
|
||||
@RegisterExtension
|
||||
@@ -108,21 +111,23 @@ public abstract class ResourceFlowTestCase<F extends Flow, R extends EppResource
|
||||
.that(logHandler)
|
||||
.hasLogAtLevelWithMessage(Level.INFO, "FLOW-LOG-SIGNATURE-METADATA")
|
||||
.which()
|
||||
.contains("\"clientId\":" + JSONValue.toJSONString(registrarId));
|
||||
.contains("\"clientId\":" + GSON.toJson(registrarId));
|
||||
}
|
||||
|
||||
protected void assertTldsFieldLogged(String... tlds) {
|
||||
assertAboutLogs().that(logHandler)
|
||||
assertAboutLogs()
|
||||
.that(logHandler)
|
||||
.hasLogAtLevelWithMessage(Level.INFO, "FLOW-LOG-SIGNATURE-METADATA")
|
||||
.which()
|
||||
.contains("\"tlds\":" + JSONValue.toJSONString(ImmutableList.copyOf(tlds)));
|
||||
.contains("\"tlds\":" + GSON.toJson(ImmutableList.copyOf(tlds)));
|
||||
}
|
||||
|
||||
protected void assertIcannReportingActivityFieldLogged(String fieldName) {
|
||||
assertAboutLogs().that(logHandler)
|
||||
assertAboutLogs()
|
||||
.that(logHandler)
|
||||
.hasLogAtLevelWithMessage(Level.INFO, "FLOW-LOG-SIGNATURE-METADATA")
|
||||
.which()
|
||||
.contains("\"icannActivityReportField\":" + JSONValue.toJSONString(fieldName));
|
||||
.contains("\"icannActivityReportField\":" + GSON.toJson(fieldName));
|
||||
}
|
||||
|
||||
protected void assertLastHistoryContainsResource(EppResource resource) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import static google.registry.model.billing.BillingBase.Flag.RESERVED;
|
||||
import static google.registry.model.billing.BillingBase.Flag.SUNRISE;
|
||||
import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.NONPREMIUM;
|
||||
import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.SPECIFIED;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureName.FORBID_INSECURE_ALGORITHMS_RFC_9904;
|
||||
import static google.registry.model.domain.fee.Fee.FEE_EXTENSION_URIS;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.BULK_PRICING;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO;
|
||||
@@ -52,6 +53,7 @@ import static google.registry.testing.DatabaseHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatabaseHelper.newHost;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatabaseHelper.persistFeatureFlag;
|
||||
import static google.registry.testing.DatabaseHelper.persistReservedList;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.DomainSubject.assertAboutDomains;
|
||||
@@ -150,6 +152,7 @@ import google.registry.model.billing.BillingBase.Reason;
|
||||
import google.registry.model.billing.BillingBase.RenewalPriceBehavior;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingRecurrence;
|
||||
import google.registry.model.common.FeatureFlag.FeatureStatus;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
@@ -794,7 +797,11 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.that(domain)
|
||||
.hasExactlyDsData(
|
||||
DomainDsData.create(
|
||||
12345, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))
|
||||
12345,
|
||||
8,
|
||||
2,
|
||||
base16()
|
||||
.decode("D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A"))
|
||||
.cloneWithDomainRepoId(domain.getRepoId()));
|
||||
}
|
||||
|
||||
@@ -957,6 +964,30 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_secDnsSha1DigestType() throws Exception {
|
||||
setEppInput("domain_create_dsdata_sha1.xml");
|
||||
persistHosts();
|
||||
persistFeatureFlag(FORBID_INSECURE_ALGORITHMS_RFC_9904, FeatureStatus.ACTIVE);
|
||||
EppException thrown = assertThrows(InvalidDsRecordException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_secDnsSha1_flagInactive() throws Exception {
|
||||
setEppInput("domain_create_dsdata_sha1.xml");
|
||||
persistHosts();
|
||||
persistFeatureFlag(FORBID_INSECURE_ALGORITHMS_RFC_9904, FeatureStatus.INACTIVE);
|
||||
doSuccessfulTest("tld");
|
||||
Domain domain = reloadResourceByForeignKey();
|
||||
assertAboutDomains()
|
||||
.that(domain)
|
||||
.hasExactlyDsData(
|
||||
DomainDsData.create(
|
||||
12345, 8, 1, base16().decode("49FD46E6C4B45C55D4AC49FD46E6C4B45C55D4AC"))
|
||||
.cloneWithDomainRepoId(domain.getRepoId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_secDnsInvalidAlgorithm() throws Exception {
|
||||
setEppInput("domain_create_dsdata_bad_algorithms.xml");
|
||||
@@ -965,6 +996,34 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_secDnsForbiddenAlgorithm() throws Exception {
|
||||
setEppInput("domain_create_dsdata_forbidden_algorithm.xml");
|
||||
persistHosts();
|
||||
persistFeatureFlag(FORBID_INSECURE_ALGORITHMS_RFC_9904, FeatureStatus.ACTIVE);
|
||||
EppException thrown = assertThrows(InvalidDsRecordException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_secDnsForbiddenAlgorithm_flagInactive() throws Exception {
|
||||
setEppInput("domain_create_dsdata_forbidden_algorithm.xml");
|
||||
persistHosts();
|
||||
persistFeatureFlag(FORBID_INSECURE_ALGORITHMS_RFC_9904, FeatureStatus.INACTIVE);
|
||||
doSuccessfulTest("tld");
|
||||
Domain domain = reloadResourceByForeignKey();
|
||||
assertAboutDomains()
|
||||
.that(domain)
|
||||
.hasExactlyDsData(
|
||||
DomainDsData.create(
|
||||
12345,
|
||||
1,
|
||||
2,
|
||||
base16()
|
||||
.decode("D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A"))
|
||||
.cloneWithDomainRepoId(domain.getRepoId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_wrongExtension() {
|
||||
setEppInput("domain_create_wrong_extension.xml");
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.domain;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.flows.domain.DomainFlowTmchUtils.SignedMarksListEmptyException;
|
||||
import google.registry.flows.domain.DomainFlowTmchUtils.SignedMarksMustBeEncodedException;
|
||||
import google.registry.flows.domain.DomainFlowTmchUtils.TooManySignedMarksException;
|
||||
import google.registry.model.smd.AbstractSignedMark;
|
||||
import java.time.Instant;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
class DomainFlowTmchUtilsTest {
|
||||
|
||||
private final DomainFlowTmchUtils tmchUtils = new DomainFlowTmchUtils(null);
|
||||
|
||||
@Test
|
||||
void test_verifySignedMarks_emptyList() {
|
||||
assertThrows(
|
||||
SignedMarksListEmptyException.class,
|
||||
() -> tmchUtils.verifySignedMarks(ImmutableList.of(), "example", Instant.now()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_verifySignedMarks_tooManyMarks() {
|
||||
AbstractSignedMark mark1 = Mockito.mock(AbstractSignedMark.class);
|
||||
AbstractSignedMark mark2 = Mockito.mock(AbstractSignedMark.class);
|
||||
assertThrows(
|
||||
TooManySignedMarksException.class,
|
||||
() ->
|
||||
tmchUtils.verifySignedMarks(ImmutableList.of(mark1, mark2), "example", Instant.now()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void test_verifySignedMarks_notEncoded() {
|
||||
AbstractSignedMark mark1 = Mockito.mock(AbstractSignedMark.class);
|
||||
assertThrows(
|
||||
SignedMarksMustBeEncodedException.class,
|
||||
() -> tmchUtils.verifySignedMarks(ImmutableList.of(mark1), "example", Instant.now()));
|
||||
}
|
||||
}
|
||||
@@ -98,6 +98,8 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Domain> {
|
||||
"UNIT", "y");
|
||||
|
||||
private static final Pattern OK_PATTERN = Pattern.compile("\"ok\"");
|
||||
private static final String SHA_256_DIGEST =
|
||||
"D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A";
|
||||
|
||||
private Host host1;
|
||||
private Host host2;
|
||||
@@ -314,8 +316,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Domain> {
|
||||
domain
|
||||
.asBuilder()
|
||||
.setDsData(
|
||||
ImmutableSet.of(
|
||||
DomainDsData.create(12345, 3, 1, base16().decode("49FD46E6C4B45C55D4AC"))))
|
||||
ImmutableSet.of(DomainDsData.create(12345, 8, 2, base16().decode(SHA_256_DIGEST))))
|
||||
.setNameservers(ImmutableSet.of(host1.createVKey(), host3.createVKey()))
|
||||
.build());
|
||||
doSuccessfulTest("domain_info_response_dsdata.xml", false);
|
||||
@@ -519,8 +520,7 @@ class DomainInfoFlowTest extends ResourceFlowTestCase<DomainInfoFlow, Domain> {
|
||||
"TheRegistrar",
|
||||
null))
|
||||
.setDsData(
|
||||
ImmutableSet.of(
|
||||
DomainDsData.create(12345, 3, 1, base16().decode("49FD46E6C4B45C55D4AC"))))
|
||||
ImmutableSet.of(DomainDsData.create(12345, 8, 2, base16().decode(SHA_256_DIGEST))))
|
||||
.build());
|
||||
doSuccessfulTest("domain_info_response_dsdata_addperiod.xml", false);
|
||||
}
|
||||
|
||||
@@ -203,6 +203,29 @@ public class DomainPricingLogicTest {
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainCreatePrice_discountPriceAllocationToken_oneYearCreate_moreDiscountYears()
|
||||
throws EppException {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123_more_discount")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("default.example")
|
||||
.setDiscountPrice(Money.of(USD, 5))
|
||||
.setDiscountYears(2)
|
||||
.setRegistrationBehavior(RegistrationBehavior.DEFAULT)
|
||||
.build());
|
||||
assertThat(
|
||||
domainPricingLogic.getCreatePrice(
|
||||
tld, "default.example", clock.now(), 1, false, false, Optional.of(allocationToken)))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(new BigDecimal("5.00"), CREATE, false))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainRenewPrice_oneYear_standardDomain_noBilling_isStandardPrice()
|
||||
throws EppException {
|
||||
@@ -1093,4 +1116,23 @@ public class DomainPricingLogicTest {
|
||||
.getRenewCost())
|
||||
.isEqualTo(Money.of(USD, 5));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDomainRenewPrice_specifiedToken_multiYear() throws Exception {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123_multi")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("premium.example")
|
||||
.setRenewalPriceBehavior(SPECIFIED)
|
||||
.setRenewalPrice(Money.of(USD, 5))
|
||||
.build());
|
||||
assertThat(
|
||||
domainPricingLogic
|
||||
.getRenewPrice(
|
||||
tld, "premium.example", clock.now(), 5, null, Optional.of(allocationToken))
|
||||
.getRenewCost())
|
||||
.isEqualTo(Money.of(USD, 25));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import static com.google.common.collect.Sets.union;
|
||||
import static com.google.common.io.BaseEncoding.base16;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ForeignKeyUtils.loadResource;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureName.FORBID_INSECURE_ALGORITHMS_RFC_9904;
|
||||
import static google.registry.model.eppcommon.StatusValue.CLIENT_DELETE_PROHIBITED;
|
||||
import static google.registry.model.eppcommon.StatusValue.CLIENT_HOLD;
|
||||
import static google.registry.model.eppcommon.StatusValue.CLIENT_RENEW_PROHIBITED;
|
||||
@@ -46,6 +47,7 @@ import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveSubordinateHost;
|
||||
import static google.registry.testing.DatabaseHelper.persistDeletedDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistFeatureFlag;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.DomainSubject.assertAboutDomains;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
@@ -94,6 +96,7 @@ import google.registry.flows.exceptions.ResourceStatusProhibitsOperationExceptio
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.billing.BillingBase.Reason;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.common.FeatureFlag.FeatureStatus;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainAuthInfo;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
@@ -115,6 +118,9 @@ import org.junit.jupiter.api.Test;
|
||||
/** Unit tests for {@link DomainUpdateFlow}. */
|
||||
class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain> {
|
||||
|
||||
private static final String SHA_256_DIGEST =
|
||||
"D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A";
|
||||
|
||||
private static final DomainDsData SOME_DSDATA =
|
||||
DomainDsData.create(
|
||||
1,
|
||||
@@ -124,9 +130,9 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
private static final ImmutableMap<String, String> OTHER_DSDATA_TEMPLATE_MAP =
|
||||
ImmutableMap.of(
|
||||
"KEY_TAG", "12346",
|
||||
"ALG", "3",
|
||||
"DIGEST_TYPE", "1",
|
||||
"DIGEST", "A94A8FE5CCB19BA61C4C0873D391E987982FBBD3");
|
||||
"ALG", "8",
|
||||
"DIGEST_TYPE", "2",
|
||||
"DIGEST", SHA_256_DIGEST);
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
@@ -453,18 +459,9 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_dsdata_add.xml",
|
||||
null,
|
||||
ImmutableSet.of(
|
||||
DomainDsData.create(
|
||||
12346, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
|
||||
ImmutableSet.of(DomainDsData.create(12346, 8, 2, base16().decode(SHA_256_DIGEST))),
|
||||
ImmutableMap.of(
|
||||
"KEY_TAG",
|
||||
"12346",
|
||||
"ALG",
|
||||
"3",
|
||||
"DIGEST_TYPE",
|
||||
"1",
|
||||
"DIGEST",
|
||||
"A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"),
|
||||
"KEY_TAG", "12346", "ALG", "8", "DIGEST_TYPE", "2", "DIGEST", SHA_256_DIGEST),
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -474,18 +471,9 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
"domain_update_dsdata_add.xml",
|
||||
ImmutableSet.of(SOME_DSDATA),
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DomainDsData.create(
|
||||
12346, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
|
||||
SOME_DSDATA, DomainDsData.create(12346, 8, 2, base16().decode(SHA_256_DIGEST))),
|
||||
ImmutableMap.of(
|
||||
"KEY_TAG",
|
||||
"12346",
|
||||
"ALG",
|
||||
"3",
|
||||
"DIGEST_TYPE",
|
||||
"1",
|
||||
"DIGEST",
|
||||
"A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"),
|
||||
"KEY_TAG", "12346", "ALG", "8", "DIGEST_TYPE", "2", "DIGEST", SHA_256_DIGEST),
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -660,11 +648,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
union(
|
||||
commonDsData,
|
||||
ImmutableSet.of(
|
||||
DomainDsData.create(
|
||||
12346,
|
||||
3,
|
||||
1,
|
||||
base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))))),
|
||||
DomainDsData.create(12346, 8, 2, base16().decode(SHA_256_DIGEST))))),
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -673,9 +657,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_dsdata_rem.xml",
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DomainDsData.create(
|
||||
12346, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
|
||||
SOME_DSDATA, DomainDsData.create(12346, 8, 2, base16().decode(SHA_256_DIGEST))),
|
||||
ImmutableSet.of(SOME_DSDATA),
|
||||
true);
|
||||
}
|
||||
@@ -686,9 +668,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_dsdata_rem_all.xml",
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DomainDsData.create(
|
||||
12346, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
|
||||
SOME_DSDATA, DomainDsData.create(12346, 8, 2, base16().decode(SHA_256_DIGEST))),
|
||||
ImmutableSet.of(),
|
||||
true);
|
||||
}
|
||||
@@ -698,13 +678,9 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
doSecDnsSuccessfulTest(
|
||||
"domain_update_dsdata_add_rem.xml",
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DomainDsData.create(
|
||||
12345, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
|
||||
SOME_DSDATA, DomainDsData.create(12345, 8, 2, base16().decode(SHA_256_DIGEST))),
|
||||
ImmutableSet.of(
|
||||
SOME_DSDATA,
|
||||
DomainDsData.create(
|
||||
12346, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))),
|
||||
SOME_DSDATA, DomainDsData.create(12346, 8, 2, base16().decode(SHA_256_DIGEST))),
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -727,20 +703,12 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
union(
|
||||
commonDsData,
|
||||
ImmutableSet.of(
|
||||
DomainDsData.create(
|
||||
12345,
|
||||
3,
|
||||
1,
|
||||
base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))))),
|
||||
DomainDsData.create(12345, 8, 2, base16().decode(SHA_256_DIGEST))))),
|
||||
ImmutableSet.copyOf(
|
||||
union(
|
||||
commonDsData,
|
||||
ImmutableSet.of(
|
||||
DomainDsData.create(
|
||||
12346,
|
||||
3,
|
||||
1,
|
||||
base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"))))),
|
||||
DomainDsData.create(12346, 8, 2, base16().decode(SHA_256_DIGEST))))),
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -915,6 +883,41 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_secDnsSha1DigestType() throws Exception {
|
||||
setEppInput(
|
||||
"domain_update_dsdata_add.xml",
|
||||
ImmutableMap.of(
|
||||
"KEY_TAG", "12346",
|
||||
"ALG", "3",
|
||||
"DIGEST_TYPE", "1",
|
||||
"DIGEST", "A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"));
|
||||
persistResource(DatabaseHelper.newDomain(getUniqueIdFromCommand()));
|
||||
persistFeatureFlag(FORBID_INSECURE_ALGORITHMS_RFC_9904, FeatureStatus.ACTIVE);
|
||||
EppException thrown = assertThrows(InvalidDsRecordException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_secDnsSha1_flagInactive() throws Exception {
|
||||
setEppInput(
|
||||
"domain_update_dsdata_add.xml",
|
||||
ImmutableMap.of(
|
||||
"KEY_TAG", "12346",
|
||||
"ALG", "3",
|
||||
"DIGEST_TYPE", "1",
|
||||
"DIGEST", "A94A8FE5CCB19BA61C4C0873D391E987982FBBD3"));
|
||||
persistResource(DatabaseHelper.newDomain(getUniqueIdFromCommand()));
|
||||
persistFeatureFlag(FORBID_INSECURE_ALGORITHMS_RFC_9904, FeatureStatus.INACTIVE);
|
||||
runFlow();
|
||||
Domain domain = reloadResourceByForeignKey();
|
||||
assertAboutDomains()
|
||||
.that(domain)
|
||||
.hasExactlyDsData(
|
||||
DomainDsData.create(
|
||||
12346, 3, 1, base16().decode("A94A8FE5CCB19BA61C4C0873D391E987982FBBD3")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_secDnsMultipleInvalidDigestTypes() throws Exception {
|
||||
setEppInput("domain_update_dsdata_add.xml", OTHER_DSDATA_TEMPLATE_MAP);
|
||||
@@ -938,7 +941,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
persistResource(
|
||||
DatabaseHelper.newDomain(getUniqueIdFromCommand())
|
||||
.asBuilder()
|
||||
.setDsData(ImmutableSet.of(DomainDsData.create(1, 2, 1, new byte[] {0, 1, 2})))
|
||||
.setDsData(ImmutableSet.of(DomainDsData.create(1, 2, 2, new byte[] {0, 1, 2})))
|
||||
.build());
|
||||
EppException thrown = assertThrows(InvalidDsRecordException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
@@ -955,7 +958,7 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
.asBuilder()
|
||||
.setDsData(
|
||||
ImmutableSet.of(
|
||||
DomainDsData.create(1, 2, 1, new byte[] {0, 1, 2, 3, 4}),
|
||||
DomainDsData.create(1, 2, 2, new byte[] {0, 1, 2, 3, 4}),
|
||||
DomainDsData.create(2, 2, 2, new byte[] {5, 6, 7})))
|
||||
.build());
|
||||
EppException thrown = assertThrows(InvalidDsRecordException.class, this::runFlow);
|
||||
@@ -979,6 +982,70 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_secDnsForbiddenAlgorithm() throws Exception {
|
||||
setEppInput("domain_update_dsdata_add.xml", OTHER_DSDATA_TEMPLATE_MAP);
|
||||
persistResource(
|
||||
DatabaseHelper.newDomain(getUniqueIdFromCommand())
|
||||
.asBuilder()
|
||||
.setDsData(
|
||||
ImmutableSet.of(DomainDsData.create(1, 1, 2, base16().decode(SHA_256_DIGEST))))
|
||||
.build());
|
||||
persistFeatureFlag(FORBID_INSECURE_ALGORITHMS_RFC_9904, FeatureStatus.ACTIVE);
|
||||
EppException thrown = assertThrows(InvalidDsRecordException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_secDnsForbiddenAlgorithm_flagInactive() throws Exception {
|
||||
setEppInput("domain_update_dsdata_add.xml", OTHER_DSDATA_TEMPLATE_MAP);
|
||||
persistResource(
|
||||
DatabaseHelper.newDomain(getUniqueIdFromCommand())
|
||||
.asBuilder()
|
||||
.setDsData(
|
||||
ImmutableSet.of(DomainDsData.create(1, 1, 2, base16().decode(SHA_256_DIGEST))))
|
||||
.build());
|
||||
persistFeatureFlag(FORBID_INSECURE_ALGORITHMS_RFC_9904, FeatureStatus.INACTIVE);
|
||||
runFlow();
|
||||
Domain domain = reloadResourceByForeignKey();
|
||||
assertAboutDomains()
|
||||
.that(domain)
|
||||
.hasExactlyDsData(
|
||||
DomainDsData.create(1, 1, 2, base16().decode(SHA_256_DIGEST)),
|
||||
DomainDsData.create(12346, 8, 2, base16().decode(SHA_256_DIGEST)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_unrelatedUpdate_existingForbiddenAlgorithm() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistResource(
|
||||
persistDomain()
|
||||
.asBuilder()
|
||||
.setDsData(
|
||||
ImmutableSet.of(DomainDsData.create(1, 1, 2, base16().decode(SHA_256_DIGEST))))
|
||||
.build());
|
||||
persistFeatureFlag(FORBID_INSECURE_ALGORITHMS_RFC_9904, FeatureStatus.ACTIVE);
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(InvalidDsRecordException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_unrelatedUpdate_existingForbiddenAlgorithm_flagInactive() throws Exception {
|
||||
persistReferencedEntities();
|
||||
persistResource(
|
||||
persistDomain()
|
||||
.asBuilder()
|
||||
.setDsData(
|
||||
ImmutableSet.of(DomainDsData.create(1, 1, 2, base16().decode(SHA_256_DIGEST))))
|
||||
.build());
|
||||
runFlow();
|
||||
Domain updatedDomain = reloadResourceByForeignKey();
|
||||
assertAboutDomains()
|
||||
.that(updatedDomain)
|
||||
.hasExactlyDsData(DomainDsData.create(1, 1, 2, base16().decode(SHA_256_DIGEST)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_secDnsMultipleInvalidAlgorithms() throws Exception {
|
||||
setEppInput("domain_update_dsdata_add.xml", OTHER_DSDATA_TEMPLATE_MAP);
|
||||
|
||||
@@ -48,7 +48,7 @@ import google.registry.flows.host.HostFlowUtils.HostNameNotPunyCodedException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameTooLongException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException;
|
||||
import google.registry.flows.host.HostFlowUtils.InvalidHostNameException;
|
||||
import google.registry.flows.host.HostFlowUtils.LoopbackIpNotValidForHostException;
|
||||
import google.registry.flows.host.HostFlowUtils.IpAddressNotRoutableException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainInPendingDeleteException;
|
||||
import google.registry.model.ForeignKeyUtils;
|
||||
@@ -354,22 +354,62 @@ class HostCreateFlowTest extends ResourceFlowTestCase<HostCreateFlow, Host> {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_localhostInetAddress_ipv4() {
|
||||
void testFailure_loopbackInetAddress_ipv4() {
|
||||
createTld("tld");
|
||||
persistActiveDomain("example.tld");
|
||||
setEppHostCreateInput("ns1.example.tld", "<host:addr ip=\"v4\">127.0.0.1</host:addr>");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(LoopbackIpNotValidForHostException.class, this::runFlow))
|
||||
.that(assertThrows(IpAddressNotRoutableException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_localhostInetAddress_ipv6() {
|
||||
void testFailure_loopbackInetAddress_ipv6() {
|
||||
createTld("tld");
|
||||
persistActiveDomain("example.tld");
|
||||
setEppHostCreateInput("ns1.example.tld", "<host:addr ip=\"v6\">::1</host:addr>");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(LoopbackIpNotValidForHostException.class, this::runFlow))
|
||||
.that(assertThrows(IpAddressNotRoutableException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_linkLocalInetAddress_ipv4() {
|
||||
createTld("tld");
|
||||
persistActiveDomain("example.tld");
|
||||
setEppHostCreateInput("ns1.example.tld", "<host:addr ip=\"v4\">169.254.1.1</host:addr>");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(IpAddressNotRoutableException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_linkLocalInetAddress_ipv6() {
|
||||
createTld("tld");
|
||||
persistActiveDomain("example.tld");
|
||||
setEppHostCreateInput("ns1.example.tld", "<host:addr ip=\"v6\">fe80::1</host:addr>");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(IpAddressNotRoutableException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_privateInetAddress_ipv4() {
|
||||
createTld("tld");
|
||||
persistActiveDomain("example.tld");
|
||||
setEppHostCreateInput("ns1.example.tld", "<host:addr ip=\"v4\">192.168.1.1</host:addr>");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(IpAddressNotRoutableException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_anyLocalInetAddress_ipv4() {
|
||||
createTld("tld");
|
||||
persistActiveDomain("example.tld");
|
||||
setEppHostCreateInput("ns1.example.tld", "<host:addr ip=\"v4\">0.0.0.0</host:addr>");
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(IpAddressNotRoutableException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.testing.HostSubject.assertAboutHosts;
|
||||
import static google.registry.util.DateTimeUtils.minusDays;
|
||||
import static google.registry.util.DateTimeUtils.plusDays;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@@ -42,6 +43,8 @@ import google.registry.flows.host.HostFlowUtils.HostNameNotLowerCaseException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameNotNormalizedException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameNotPunyCodedException;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.GracePeriod;
|
||||
import google.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.model.reporting.HistoryEntry.Type;
|
||||
@@ -311,6 +314,30 @@ class HostDeleteFlowTest extends ResourceFlowTestCase<HostDeleteFlow, Host> {
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_failfastWhenLinkedToDomainInRedemption() throws Exception {
|
||||
createTld("tld");
|
||||
Host host = persistActiveHost("ns1.example.tld");
|
||||
Domain domain = persistResource(DatabaseHelper.newDomain("example.tld"));
|
||||
persistResource(
|
||||
domain
|
||||
.asBuilder()
|
||||
.setNameservers(ImmutableSet.of(host.createVKey()))
|
||||
.setDeletionTime(plusDays(clock.now(), 35))
|
||||
.addGracePeriod(
|
||||
GracePeriod.create(
|
||||
GracePeriodStatus.REDEMPTION,
|
||||
domain.getRepoId(),
|
||||
plusDays(clock.now(), 1),
|
||||
"TheRegistrar",
|
||||
null))
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.PENDING_DELETE))
|
||||
.build());
|
||||
|
||||
EppException thrown = assertThrows(ResourceToDeleteIsReferencedException.class, this::runFlow);
|
||||
assertAboutEppExceptions().that(thrown).marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_nonLowerCaseHostname() {
|
||||
setEppInput("host_delete.xml", ImmutableMap.of("HOSTNAME", "NS1.EXAMPLE.NET"));
|
||||
|
||||
@@ -65,7 +65,7 @@ import google.registry.flows.host.HostFlowUtils.HostNameNotNormalizedException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameNotPunyCodedException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameTooLongException;
|
||||
import google.registry.flows.host.HostFlowUtils.HostNameTooShallowException;
|
||||
import google.registry.flows.host.HostFlowUtils.LoopbackIpNotValidForHostException;
|
||||
import google.registry.flows.host.HostFlowUtils.IpAddressNotRoutableException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainDoesNotExistException;
|
||||
import google.registry.flows.host.HostFlowUtils.SuperordinateDomainInPendingDeleteException;
|
||||
import google.registry.flows.host.HostUpdateFlow.CannotAddIpToExternalHostException;
|
||||
@@ -1391,24 +1391,68 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, Host> {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_localhostInetAddress_ipv4() throws Exception {
|
||||
void testFailure_loopbackInetAddress_ipv4() throws Exception {
|
||||
createTld("tld");
|
||||
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld", "ns2.example.tld", "<host:addr ip=\"v4\">127.0.0.1</host:addr>", null);
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(LoopbackIpNotValidForHostException.class, this::runFlow))
|
||||
.that(assertThrows(IpAddressNotRoutableException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_localhostInetAddress_ipv6() throws Exception {
|
||||
void testFailure_loopbackInetAddress_ipv6() throws Exception {
|
||||
createTld("tld");
|
||||
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld", "ns2.example.tld", "<host:addr ip=\"v6\">::1</host:addr>", null);
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(LoopbackIpNotValidForHostException.class, this::runFlow))
|
||||
.that(assertThrows(IpAddressNotRoutableException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_linkLocalInetAddress_ipv4() throws Exception {
|
||||
createTld("tld");
|
||||
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld", "ns2.example.tld", "<host:addr ip=\"v4\">169.254.1.1</host:addr>", null);
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(IpAddressNotRoutableException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_linkLocalInetAddress_ipv6() throws Exception {
|
||||
createTld("tld");
|
||||
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld", "ns2.example.tld", "<host:addr ip=\"v6\">fe80::1</host:addr>", null);
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(IpAddressNotRoutableException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_privateInetAddress_ipv4() throws Exception {
|
||||
createTld("tld");
|
||||
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld", "ns2.example.tld", "<host:addr ip=\"v4\">192.168.1.1</host:addr>", null);
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(IpAddressNotRoutableException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_anyLocalInetAddress_ipv4() throws Exception {
|
||||
createTld("tld");
|
||||
persistActiveSubordinateHost(oldHostName(), persistActiveDomain("example.tld"));
|
||||
setEppHostUpdateInput(
|
||||
"ns1.example.tld", "ns2.example.tld", "<host:addr ip=\"v4\">0.0.0.0</host:addr>", null);
|
||||
assertAboutEppExceptions()
|
||||
.that(assertThrows(IpAddressNotRoutableException.class, this::runFlow))
|
||||
.marshalsToXml();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.flows.picker;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import google.registry.flows.Flow;
|
||||
import google.registry.flows.domain.DomainCheckFlow;
|
||||
import google.registry.flows.domain.DomainCreateFlow;
|
||||
import google.registry.model.domain.DomainCommand;
|
||||
import google.registry.model.eppcommon.EppXmlTransformer;
|
||||
import google.registry.model.eppinput.EppInput;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link FlowPicker}. */
|
||||
class FlowPickerTest {
|
||||
|
||||
@Test
|
||||
void testGetFlowClass_matchingWrapperAndCommand_returnsFlow() throws Exception {
|
||||
EppInput checkEppInput = EppInput.create(EppInput.Check.create(new DomainCommand.Check()));
|
||||
Class<? extends Flow> checkFlow = FlowPicker.getFlowClass(checkEppInput);
|
||||
assertThat(checkFlow).isEqualTo(DomainCheckFlow.class);
|
||||
|
||||
EppInput createEppInput = EppInput.create(EppInput.Create.create(new DomainCommand.Create()));
|
||||
Class<? extends Flow> createFlow = FlowPicker.getFlowClass(createEppInput);
|
||||
assertThat(createFlow).isEqualTo(DomainCreateFlow.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetFlowClass_mismatchedWrapperAndCommand_throwsSyntaxErrorException() {
|
||||
EppInput mismatchedEppInput1 =
|
||||
EppInput.create(EppInput.Check.create(new DomainCommand.Create()));
|
||||
assertThat(
|
||||
assertThrows(
|
||||
FlowPicker.MismatchedCommandException.class,
|
||||
() -> FlowPicker.getFlowClass(mismatchedEppInput1)))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("EPP command wrapper <check> does not match resource command <create>");
|
||||
|
||||
EppInput mismatchedEppInput2 =
|
||||
EppInput.create(EppInput.Create.create(new DomainCommand.Check()));
|
||||
assertThat(
|
||||
assertThrows(
|
||||
FlowPicker.MismatchedCommandException.class,
|
||||
() -> FlowPicker.getFlowClass(mismatchedEppInput2)))
|
||||
.hasMessageThat()
|
||||
.contains("EPP command wrapper <create> does not match resource command <check>");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetFlowClass_mismatchedXml_throwsMismatchedCommandException() throws Exception {
|
||||
String mismatchedXml =
|
||||
"""
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.com</domain:name>
|
||||
<domain:authInfo>
|
||||
<domain:pw>fooBAR123</domain:pw>
|
||||
</domain:authInfo>
|
||||
</domain:create>
|
||||
</check>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
""";
|
||||
|
||||
// Verify JAXB successfully unmarshals the mismatched XML without throwing any errors
|
||||
EppInput eppInput = EppXmlTransformer.unmarshal(EppInput.class, mismatchedXml.getBytes(UTF_8));
|
||||
assertThat(eppInput).isNotNull();
|
||||
|
||||
// Verify that FlowPicker intercepts the unmarshalled input and blocks it
|
||||
assertThat(
|
||||
assertThrows(
|
||||
FlowPicker.MismatchedCommandException.class,
|
||||
() -> FlowPicker.getFlowClass(eppInput)))
|
||||
.hasMessageThat()
|
||||
.contains("EPP command wrapper <check> does not match resource command <create>");
|
||||
}
|
||||
}
|
||||
@@ -20,13 +20,12 @@ import static google.registry.model.common.FeatureFlag.FeatureName.PROHIBIT_CONT
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.testing.DatabaseHelper.deleteResource;
|
||||
import static google.registry.testing.DatabaseHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatabaseHelper.persistFeatureFlag;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
import static google.registry.util.DateTimeUtils.START_INSTANT;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import google.registry.flows.EppException;
|
||||
import google.registry.flows.EppException.UnimplementedExtensionException;
|
||||
import google.registry.flows.EppException.UnimplementedObjectServiceException;
|
||||
@@ -39,7 +38,6 @@ import google.registry.flows.session.LoginFlow.BadRegistrarIdException;
|
||||
import google.registry.flows.session.LoginFlow.RegistrarAccountNotActiveException;
|
||||
import google.registry.flows.session.LoginFlow.TooManyFailedLoginsException;
|
||||
import google.registry.flows.session.LoginFlow.UnsupportedLanguageException;
|
||||
import google.registry.model.common.FeatureFlag;
|
||||
import google.registry.model.common.FeatureFlag.FeatureStatus;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
@@ -61,11 +59,7 @@ public abstract class LoginFlowTestCase extends FlowTestCase<LoginFlow> {
|
||||
sessionMetadata.setRegistrarId(null); // Don't implicitly log in (all other flows need to).
|
||||
registrar = loadRegistrar("NewRegistrar");
|
||||
registrarBuilder = registrar.asBuilder();
|
||||
persistResource(
|
||||
new FeatureFlag.Builder()
|
||||
.setFeatureName(PROHIBIT_CONTACT_OBJECTS_ON_LOGIN)
|
||||
.setStatusMap(ImmutableSortedMap.of(START_INSTANT, FeatureStatus.ACTIVE))
|
||||
.build());
|
||||
persistFeatureFlag(PROHIBIT_CONTACT_OBJECTS_ON_LOGIN, FeatureStatus.ACTIVE);
|
||||
}
|
||||
|
||||
// Can't inline this since it may be overridden in subclasses.
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.model.domain.fee;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import google.registry.model.domain.fee.BaseFee.FeeType;
|
||||
import java.math.BigDecimal;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class FeeTest {
|
||||
|
||||
@Test
|
||||
void testCreate_success() {
|
||||
Fee fee = Fee.create(BigDecimal.valueOf(10.00), FeeType.CREATE, false);
|
||||
assertThat(fee.getCost()).isEqualTo(BigDecimal.valueOf(10.00));
|
||||
assertThat(fee.getType()).isEqualTo(FeeType.CREATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreate_nullCost() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(IllegalArgumentException.class, () -> Fee.create(null, FeeType.CREATE, false));
|
||||
assertThat(thrown).hasMessageThat().contains("Cost cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreate_negativeCost() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> Fee.create(BigDecimal.valueOf(-5.00), FeeType.CREATE, false));
|
||||
assertThat(thrown).hasMessageThat().contains("Cost must be a non-negative number");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreate_nullType() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> Fee.create(BigDecimal.valueOf(10.00), null, false));
|
||||
assertThat(thrown).hasMessageThat().contains("Must specify the type of the fee");
|
||||
}
|
||||
}
|
||||
@@ -283,15 +283,15 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
|
||||
private JsonObject generateExpectedJsonForTwoDomainsNsReply() {
|
||||
return jsonFileBuilder()
|
||||
.addDomain("cat.example", "F-EXAMPLE")
|
||||
.addDomain("cat.lol", "6-LOL")
|
||||
.addDomain("cat.example", domainCatExample.getRepoId())
|
||||
.addDomain("cat.lol", domainCatLol.getRepoId())
|
||||
.load("rdap_domains_two.json");
|
||||
}
|
||||
|
||||
private JsonObject generateExpectedJsonForTwoDomainsCatStarReplySql() {
|
||||
return jsonFileBuilder()
|
||||
.addDomain("cat.lol", "6-LOL")
|
||||
.addDomain("cat2.lol", "B-LOL")
|
||||
.addDomain("cat.lol", domainCatLol.getRepoId())
|
||||
.addDomain("cat2.lol", domainCatLol2.getRepoId())
|
||||
.load("rdap_domains_two.json");
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
minusMonths(clock.now(), 6)));
|
||||
}
|
||||
|
||||
private void createManyDomainsAndHosts(
|
||||
private ImmutableList<Domain> createManyDomainsAndHosts(
|
||||
int numActiveDomains, int numTotalDomainsPerActiveDomain, int numHosts) {
|
||||
ImmutableSet.Builder<VKey<Host>> hostKeysBuilder = new ImmutableSet.Builder<>();
|
||||
ImmutableSet.Builder<String> subordinateHostnamesBuilder = new ImmutableSet.Builder<>();
|
||||
@@ -340,7 +340,7 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
}
|
||||
domainsBuilder.add(builder.build());
|
||||
}
|
||||
persistResources(domainsBuilder.build());
|
||||
return persistResources(domainsBuilder.build());
|
||||
}
|
||||
|
||||
private void checkNumberOfDomainsInResult(JsonObject obj, int expected) {
|
||||
@@ -353,10 +353,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
requestType,
|
||||
queryString,
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.lol", "6-LOL")
|
||||
.addDomain("cat.lol", domainCatLol.getRepoId())
|
||||
.addRegistrar("Yes Virginia <script>")
|
||||
.addNameserver("ns1.cat.lol", "2-ROID")
|
||||
.addNameserver("ns2.cat.lol", "4-ROID")
|
||||
.addNameserver("ns1.cat.lol", hostNs1CatLol.getRepoId())
|
||||
.addNameserver("ns2.cat.lol", hostNs2CatLol.getRepoId())
|
||||
.setNextQuery(queryString)
|
||||
.load(filename));
|
||||
}
|
||||
@@ -367,10 +367,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
requestType,
|
||||
queryString,
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat2.lol", "B-LOL")
|
||||
.addDomain("cat2.lol", domainCatLol2.getRepoId())
|
||||
.addRegistrar("Yes Virginia <script>")
|
||||
.addNameserver("ns1.cat.example", "7-ROID")
|
||||
.addNameserver("ns2.dog.lol", "9-ROID")
|
||||
.addNameserver("ns1.cat.example", hostNameToHostMap.get("ns1.cat.example").getRepoId())
|
||||
.addNameserver("ns2.dog.lol", hostNameToHostMap.get("ns2.dog.lol").getRepoId())
|
||||
.setNextQuery(queryString)
|
||||
.load(filename));
|
||||
}
|
||||
@@ -679,10 +679,11 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
RequestType.NAME,
|
||||
"cat.example",
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.example", "F-EXAMPLE")
|
||||
.addDomain("cat.example", domainCatExample.getRepoId())
|
||||
.addRegistrar("St. John Chrysostom")
|
||||
.addNameserver("ns1.cat.lol", "2-ROID")
|
||||
.addNameserver("ns2.external.tld", "D-ROID")
|
||||
.addNameserver("ns1.cat.lol", hostNs1CatLol.getRepoId())
|
||||
.addNameserver(
|
||||
"ns2.external.tld", hostNameToHostMap.get("ns2.external.tld").getRepoId())
|
||||
.load("rdap_domain.json"));
|
||||
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(1L));
|
||||
}
|
||||
@@ -693,10 +694,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
RequestType.NAME,
|
||||
"cat.みんな",
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.みんな", "15-Q9JYB4C")
|
||||
.addDomain("cat.みんな", domainIdn.getRepoId())
|
||||
.addRegistrar("みんな")
|
||||
.addNameserver("ns1.cat.みんな", "11-ROID")
|
||||
.addNameserver("ns2.cat.みんな", "13-ROID")
|
||||
.addNameserver("ns1.cat.みんな", hostNameToHostMap.get("ns1.cat.xn--q9jyb4c").getRepoId())
|
||||
.addNameserver("ns2.cat.みんな", hostNameToHostMap.get("ns2.cat.xn--q9jyb4c").getRepoId())
|
||||
.load("rdap_domain_unicode_with_unicode_nameservers.json"));
|
||||
// The unicode gets translated to ASCII before getting parsed into a search pattern.
|
||||
metricPrefixLength = 15;
|
||||
@@ -709,10 +710,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
RequestType.NAME,
|
||||
"cat.xn--q9jyb4c",
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.みんな", "15-Q9JYB4C")
|
||||
.addDomain("cat.みんな", domainIdn.getRepoId())
|
||||
.addRegistrar("みんな")
|
||||
.addNameserver("ns1.cat.みんな", "11-ROID")
|
||||
.addNameserver("ns2.cat.みんな", "13-ROID")
|
||||
.addNameserver("ns1.cat.みんな", hostNameToHostMap.get("ns1.cat.xn--q9jyb4c").getRepoId())
|
||||
.addNameserver("ns2.cat.みんな", hostNameToHostMap.get("ns2.cat.xn--q9jyb4c").getRepoId())
|
||||
.load("rdap_domain_unicode_with_unicode_nameservers.json"));
|
||||
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(1L));
|
||||
}
|
||||
@@ -723,10 +724,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
RequestType.NAME,
|
||||
"cat.1.test",
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.1.test", "1B-1TEST")
|
||||
.addDomain("cat.1.test", domainMultipart.getRepoId())
|
||||
.addRegistrar("1.test")
|
||||
.addNameserver("ns1.cat.1.test", "17-ROID")
|
||||
.addNameserver("ns2.cat.2.test", "19-ROID")
|
||||
.addNameserver("ns1.cat.1.test", hostNameToHostMap.get("ns1.cat.1.test").getRepoId())
|
||||
.addNameserver("ns2.cat.2.test", hostNameToHostMap.get("ns2.cat.2.test").getRepoId())
|
||||
.load("rdap_domain.json"));
|
||||
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(1L));
|
||||
}
|
||||
@@ -737,10 +738,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
RequestType.NAME,
|
||||
"ca*.1.test",
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.1.test", "1B-1TEST")
|
||||
.addDomain("cat.1.test", domainMultipart.getRepoId())
|
||||
.addRegistrar("1.test")
|
||||
.addNameserver("ns1.cat.1.test", "17-ROID")
|
||||
.addNameserver("ns2.cat.2.test", "19-ROID")
|
||||
.addNameserver("ns1.cat.1.test", hostNameToHostMap.get("ns1.cat.1.test").getRepoId())
|
||||
.addNameserver("ns2.cat.2.test", hostNameToHostMap.get("ns2.cat.2.test").getRepoId())
|
||||
.load("rdap_domain.json"));
|
||||
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(1L));
|
||||
}
|
||||
@@ -813,10 +814,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
.that(generateActualJson(RequestType.NAME, "cat.*"))
|
||||
.isEqualTo(
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.1.test", "1B-1TEST")
|
||||
.addDomain("cat.example", "F-EXAMPLE")
|
||||
.addDomain("cat.lol", "6-LOL")
|
||||
.addDomain("cat.みんな", "15-Q9JYB4C")
|
||||
.addDomain("cat.1.test", domainMultipart.getRepoId())
|
||||
.addDomain("cat.example", domainCatExample.getRepoId())
|
||||
.addDomain("cat.lol", domainCatLol.getRepoId())
|
||||
.addDomain("cat.みんな", domainIdn.getRepoId())
|
||||
.load("rdap_domains_four_with_one_unicode.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(4L));
|
||||
@@ -851,10 +852,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
.that(generateActualJson(RequestType.NAME, "cat*"))
|
||||
.isEqualTo(
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.1.test", "1B-1TEST")
|
||||
.addDomain("cat.example", "F-EXAMPLE")
|
||||
.addDomain("cat.lol", "6-LOL")
|
||||
.addDomain("cat.みんな", "15-Q9JYB4C")
|
||||
.addDomain("cat.1.test", domainMultipart.getRepoId())
|
||||
.addDomain("cat.example", domainCatExample.getRepoId())
|
||||
.addDomain("cat.lol", domainCatLol.getRepoId())
|
||||
.addDomain("cat.みんな", domainIdn.getRepoId())
|
||||
.setNextQuery("name=cat*&cursor=Y2F0LnhuLS1xOWp5YjRj")
|
||||
.load("rdap_domains_four_with_one_unicode_truncated.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
@@ -970,15 +971,15 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
// This is not exactly desired behavior, but expected: There are enough domains to fill a full
|
||||
// result set, but there are so many deleted domains that we run out of patience before we work
|
||||
// our way through all of them.
|
||||
createManyDomainsAndHosts(4, 50, 2);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(4, 50, 2);
|
||||
rememberWildcardType("domain*.lol");
|
||||
assertAboutJson()
|
||||
.that(generateActualJson(RequestType.NAME, "domain*.lol"))
|
||||
.isEqualTo(
|
||||
jsonFileBuilder()
|
||||
.addDomain("domain100.lol", "8E-LOL")
|
||||
.addDomain("domain150.lol", "5C-LOL")
|
||||
.addDomain("domain200.lol", "2A-LOL")
|
||||
.addDomain("domain100.lol", domains.get(100).getRepoId())
|
||||
.addDomain("domain150.lol", domains.get(50).getRepoId())
|
||||
.addDomain("domain200.lol", domains.get(0).getRepoId())
|
||||
.addDomain("domainunused.lol", "unused-LOL")
|
||||
.load("rdap_incomplete_domain_result_set.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
@@ -990,28 +991,28 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
|
||||
@Test
|
||||
void testDomainMatch_nontruncatedResultsSet() {
|
||||
createManyDomainsAndHosts(4, 1, 2);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(4, 1, 2);
|
||||
runSuccessfulTestWithFourDomains(
|
||||
RequestType.NAME,
|
||||
"domain*.lol",
|
||||
"2D-LOL",
|
||||
"2C-LOL",
|
||||
"2B-LOL",
|
||||
"2A-LOL",
|
||||
domains.get(3).getRepoId(),
|
||||
domains.get(2).getRepoId(),
|
||||
domains.get(1).getRepoId(),
|
||||
domains.get(0).getRepoId(),
|
||||
"rdap_nontruncated_domains.json");
|
||||
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(4L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDomainMatch_truncatedResultsSet() {
|
||||
createManyDomainsAndHosts(5, 1, 2);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(5, 1, 2);
|
||||
runSuccessfulTestWithFourDomains(
|
||||
RequestType.NAME,
|
||||
"domain*.lol",
|
||||
"2E-LOL",
|
||||
"2D-LOL",
|
||||
"2C-LOL",
|
||||
"2B-LOL",
|
||||
domains.get(4).getRepoId(),
|
||||
domains.get(3).getRepoId(),
|
||||
domains.get(2).getRepoId(),
|
||||
domains.get(1).getRepoId(),
|
||||
"name=domain*.lol&cursor=ZG9tYWluNC5sb2w%3D",
|
||||
"rdap_domains_four_truncated.json");
|
||||
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(5L), IncompletenessWarningType.TRUNCATED);
|
||||
@@ -1019,16 +1020,16 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
|
||||
@Test
|
||||
void testDomainMatch_tldSearchOrderedProperly_sql() {
|
||||
createManyDomainsAndHosts(4, 1, 2);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(4, 1, 2);
|
||||
rememberWildcardType("*.lol");
|
||||
assertAboutJson()
|
||||
.that(generateActualJson(RequestType.NAME, "*.lol"))
|
||||
.isEqualTo(
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.lol", "6-LOL")
|
||||
.addDomain("cat2.lol", "B-LOL")
|
||||
.addDomain("domain1.lol", "2D-LOL")
|
||||
.addDomain("domain2.lol", "2C-LOL")
|
||||
.addDomain("cat.lol", domainCatLol.getRepoId())
|
||||
.addDomain("cat2.lol", domainCatLol2.getRepoId())
|
||||
.addDomain("domain1.lol", domains.get(3).getRepoId())
|
||||
.addDomain("domain2.lol", domains.get(2).getRepoId())
|
||||
.setNextQuery("name=*.lol&cursor=ZG9tYWluMi5sb2w%3D")
|
||||
.load("rdap_domains_four_truncated.json"));
|
||||
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(5L), IncompletenessWarningType.TRUNCATED);
|
||||
@@ -1038,14 +1039,14 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
void testDomainMatch_reallyTruncatedResultsSet() {
|
||||
// Don't use 10 or more domains for this test, because domain10.lol will come before
|
||||
// domain2.lol, and you'll get the wrong domains in the result set.
|
||||
createManyDomainsAndHosts(9, 1, 2);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(9, 1, 2);
|
||||
runSuccessfulTestWithFourDomains(
|
||||
RequestType.NAME,
|
||||
"domain*.lol",
|
||||
"32-LOL",
|
||||
"31-LOL",
|
||||
"30-LOL",
|
||||
"2F-LOL",
|
||||
domains.get(8).getRepoId(),
|
||||
domains.get(7).getRepoId(),
|
||||
domains.get(6).getRepoId(),
|
||||
domains.get(5).getRepoId(),
|
||||
"name=domain*.lol&cursor=ZG9tYWluNC5sb2w%3D",
|
||||
"rdap_domains_four_truncated.json");
|
||||
verifyMetrics(SearchType.BY_DOMAIN_NAME, Optional.of(5L), IncompletenessWarningType.TRUNCATED);
|
||||
@@ -1053,16 +1054,16 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
|
||||
@Test
|
||||
void testDomainMatch_truncatedResultsAfterMultipleChunks_sql() {
|
||||
createManyDomainsAndHosts(5, 6, 2);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(5, 6, 2);
|
||||
rememberWildcardType("domain*.lol");
|
||||
assertAboutJson()
|
||||
.that(generateActualJson(RequestType.NAME, "domain*.lol"))
|
||||
.isEqualTo(
|
||||
jsonFileBuilder()
|
||||
.addDomain("domain12.lol", "3C-LOL")
|
||||
.addDomain("domain18.lol", "36-LOL")
|
||||
.addDomain("domain24.lol", "30-LOL")
|
||||
.addDomain("domain30.lol", "2A-LOL")
|
||||
.addDomain("domain12.lol", domains.get(18).getRepoId())
|
||||
.addDomain("domain18.lol", domains.get(12).getRepoId())
|
||||
.addDomain("domain24.lol", domains.get(6).getRepoId())
|
||||
.addDomain("domain30.lol", domains.get(0).getRepoId())
|
||||
.setNextQuery("name=domain*.lol&cursor=ZG9tYWluMzAubG9s")
|
||||
.load("rdap_domains_four_truncated.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
@@ -1261,10 +1262,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
RequestType.NS_LDH_NAME,
|
||||
"ns1.cat.xn--q9jyb4c",
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.みんな", "15-Q9JYB4C")
|
||||
.addDomain("cat.みんな", domainIdn.getRepoId())
|
||||
.addRegistrar("みんな")
|
||||
.addNameserver("ns1.cat.みんな", "11-ROID")
|
||||
.addNameserver("ns2.cat.みんな", "13-ROID")
|
||||
.addNameserver("ns1.cat.みんな", hostNameToHostMap.get("ns1.cat.xn--q9jyb4c").getRepoId())
|
||||
.addNameserver("ns2.cat.みんな", hostNameToHostMap.get("ns2.cat.xn--q9jyb4c").getRepoId())
|
||||
.load("rdap_domain_unicode_with_unicode_nameservers.json"));
|
||||
verifyMetrics(SearchType.BY_NAMESERVER_NAME, 1, 1);
|
||||
}
|
||||
@@ -1275,10 +1276,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
RequestType.NS_LDH_NAME,
|
||||
"ns1.cat.1.test",
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.1.test", "1B-1TEST")
|
||||
.addDomain("cat.1.test", domainMultipart.getRepoId())
|
||||
.addRegistrar("1.test")
|
||||
.addNameserver("ns1.cat.1.test", "17-ROID")
|
||||
.addNameserver("ns2.cat.2.test", "19-ROID")
|
||||
.addNameserver("ns1.cat.1.test", hostNameToHostMap.get("ns1.cat.1.test").getRepoId())
|
||||
.addNameserver("ns2.cat.2.test", hostNameToHostMap.get("ns2.cat.2.test").getRepoId())
|
||||
.load("rdap_domain.json"));
|
||||
verifyMetrics(SearchType.BY_NAMESERVER_NAME, 1, 1);
|
||||
}
|
||||
@@ -1289,10 +1290,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
RequestType.NS_LDH_NAME,
|
||||
"ns*.cat.1.test",
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.1.test", "1B-1TEST")
|
||||
.addDomain("cat.1.test", domainMultipart.getRepoId())
|
||||
.addRegistrar("1.test")
|
||||
.addNameserver("ns1.cat.1.test", "17-ROID")
|
||||
.addNameserver("ns2.cat.2.test", "19-ROID")
|
||||
.addNameserver("ns1.cat.1.test", hostNameToHostMap.get("ns1.cat.1.test").getRepoId())
|
||||
.addNameserver("ns2.cat.2.test", hostNameToHostMap.get("ns2.cat.2.test").getRepoId())
|
||||
.load("rdap_domain.json"));
|
||||
verifyMetrics(SearchType.BY_NAMESERVER_NAME, 1, 1);
|
||||
}
|
||||
@@ -1430,28 +1431,28 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
|
||||
@Test
|
||||
void testNameserverMatch_nontruncatedResultsSet() {
|
||||
createManyDomainsAndHosts(4, 1, 2);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(4, 1, 2);
|
||||
runSuccessfulTestWithFourDomains(
|
||||
RequestType.NS_LDH_NAME,
|
||||
"ns1.domain1.lol",
|
||||
"2D-LOL",
|
||||
"2C-LOL",
|
||||
"2B-LOL",
|
||||
"2A-LOL",
|
||||
domains.get(3).getRepoId(),
|
||||
domains.get(2).getRepoId(),
|
||||
domains.get(1).getRepoId(),
|
||||
domains.get(0).getRepoId(),
|
||||
"rdap_nontruncated_domains.json");
|
||||
verifyMetrics(SearchType.BY_NAMESERVER_NAME, Optional.of(4L), Optional.of(1L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNameserverMatch_truncatedResultsSet() {
|
||||
createManyDomainsAndHosts(5, 1, 2);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(5, 1, 2);
|
||||
runSuccessfulTestWithFourDomains(
|
||||
RequestType.NS_LDH_NAME,
|
||||
"ns1.domain1.lol",
|
||||
"2E-LOL",
|
||||
"2D-LOL",
|
||||
"2C-LOL",
|
||||
"2B-LOL",
|
||||
domains.get(4).getRepoId(),
|
||||
domains.get(3).getRepoId(),
|
||||
domains.get(2).getRepoId(),
|
||||
domains.get(1).getRepoId(),
|
||||
"nsLdhName=ns1.domain1.lol&cursor=ZG9tYWluNC5sb2w%3D",
|
||||
"rdap_domains_four_truncated.json");
|
||||
verifyMetrics(
|
||||
@@ -1463,14 +1464,14 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
|
||||
@Test
|
||||
void testNameserverMatch_reallyTruncatedResultsSet() {
|
||||
createManyDomainsAndHosts(9, 1, 2);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(9, 1, 2);
|
||||
runSuccessfulTestWithFourDomains(
|
||||
RequestType.NS_LDH_NAME,
|
||||
"ns1.domain1.lol",
|
||||
"32-LOL",
|
||||
"31-LOL",
|
||||
"30-LOL",
|
||||
"2F-LOL",
|
||||
domains.get(8).getRepoId(),
|
||||
domains.get(7).getRepoId(),
|
||||
domains.get(6).getRepoId(),
|
||||
domains.get(5).getRepoId(),
|
||||
"nsLdhName=ns1.domain1.lol&cursor=ZG9tYWluNC5sb2w%3D",
|
||||
"rdap_domains_four_truncated.json");
|
||||
verifyMetrics(
|
||||
@@ -1484,16 +1485,16 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
void testNameserverMatch_duplicatesNotTruncated() {
|
||||
// 36 nameservers for each of 4 domains; these should translate into two fetches, which should
|
||||
// not trigger the truncation warning because all the domains will be duplicates.
|
||||
createManyDomainsAndHosts(4, 1, 36);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(4, 1, 36);
|
||||
rememberWildcardType("ns*.domain1.lol");
|
||||
assertAboutJson()
|
||||
.that(generateActualJson(RequestType.NS_LDH_NAME, "ns*.domain1.lol"))
|
||||
.isEqualTo(
|
||||
jsonFileBuilder()
|
||||
.addDomain("domain1.lol", "71-LOL")
|
||||
.addDomain("domain2.lol", "70-LOL")
|
||||
.addDomain("domain3.lol", "6F-LOL")
|
||||
.addDomain("domain4.lol", "6E-LOL")
|
||||
.addDomain("domain1.lol", domains.get(3).getRepoId())
|
||||
.addDomain("domain2.lol", domains.get(2).getRepoId())
|
||||
.addDomain("domain3.lol", domains.get(1).getRepoId())
|
||||
.addDomain("domain4.lol", domains.get(0).getRepoId())
|
||||
.load("rdap_nontruncated_domains.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(SearchType.BY_NAMESERVER_NAME, Optional.of(4L), Optional.of(36L));
|
||||
@@ -1501,14 +1502,14 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
|
||||
@Test
|
||||
void testNameserverMatch_incompleteResultsSet() {
|
||||
createManyDomainsAndHosts(2, 1, 41);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(2, 1, 41);
|
||||
rememberWildcardType("ns*.domain1.lol");
|
||||
assertAboutJson()
|
||||
.that(generateActualJson(RequestType.NS_LDH_NAME, "ns*.domain1.lol"))
|
||||
.isEqualTo(
|
||||
jsonFileBuilder()
|
||||
.addDomain("domain1.lol", "79-LOL")
|
||||
.addDomain("domain2.lol", "78-LOL")
|
||||
.addDomain("domain1.lol", domains.get(1).getRepoId())
|
||||
.addDomain("domain2.lol", domains.get(0).getRepoId())
|
||||
.load("rdap_incomplete_domains.json"));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(
|
||||
@@ -1641,10 +1642,10 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
.isEqualTo(
|
||||
wrapInSearchReply(
|
||||
jsonFileBuilder()
|
||||
.addDomain("cat.lol", "6-LOL")
|
||||
.addDomain("cat.lol", domainCatLol.getRepoId())
|
||||
.addRegistrar("Yes Virginia <script>")
|
||||
.addNameserver("ns1.cat.lol", "2-ROID")
|
||||
.addNameserver("ns2.cat.lol", "4-ROID")
|
||||
.addNameserver("ns1.cat.lol", hostNs1CatLol.getRepoId())
|
||||
.addNameserver("ns2.cat.lol", hostNs2CatLol.getRepoId())
|
||||
.load("rdap_domain.json")));
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
verifyMetrics(SearchType.BY_NAMESERVER_ADDRESS, 1, 1);
|
||||
@@ -1667,28 +1668,28 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
|
||||
@Test
|
||||
void testAddressMatch_nontruncatedResultsSet() {
|
||||
createManyDomainsAndHosts(4, 1, 2);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(4, 1, 2);
|
||||
runSuccessfulTestWithFourDomains(
|
||||
RequestType.NS_IP,
|
||||
"5.5.5.1",
|
||||
"2D-LOL",
|
||||
"2C-LOL",
|
||||
"2B-LOL",
|
||||
"2A-LOL",
|
||||
domains.get(3).getRepoId(),
|
||||
domains.get(2).getRepoId(),
|
||||
domains.get(1).getRepoId(),
|
||||
domains.get(0).getRepoId(),
|
||||
"rdap_nontruncated_domains.json");
|
||||
verifyMetrics(SearchType.BY_NAMESERVER_ADDRESS, 4, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddressMatch_truncatedResultsSet() {
|
||||
createManyDomainsAndHosts(5, 1, 2);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(5, 1, 2);
|
||||
runSuccessfulTestWithFourDomains(
|
||||
RequestType.NS_IP,
|
||||
"5.5.5.1",
|
||||
"2E-LOL",
|
||||
"2D-LOL",
|
||||
"2C-LOL",
|
||||
"2B-LOL",
|
||||
domains.get(4).getRepoId(),
|
||||
domains.get(3).getRepoId(),
|
||||
domains.get(2).getRepoId(),
|
||||
domains.get(1).getRepoId(),
|
||||
"nsIp=5.5.5.1&cursor=ZG9tYWluNC5sb2w%3D",
|
||||
"rdap_domains_four_truncated.json");
|
||||
verifyMetrics(
|
||||
@@ -1700,14 +1701,14 @@ class RdapDomainSearchActionTest extends RdapSearchActionTestCase<RdapDomainSear
|
||||
|
||||
@Test
|
||||
void testAddressMatch_reallyTruncatedResultsSet() {
|
||||
createManyDomainsAndHosts(9, 1, 2);
|
||||
ImmutableList<Domain> domains = createManyDomainsAndHosts(9, 1, 2);
|
||||
runSuccessfulTestWithFourDomains(
|
||||
RequestType.NS_IP,
|
||||
"5.5.5.1",
|
||||
"32-LOL",
|
||||
"31-LOL",
|
||||
"30-LOL",
|
||||
"2F-LOL",
|
||||
domains.get(8).getRepoId(),
|
||||
domains.get(7).getRepoId(),
|
||||
domains.get(6).getRepoId(),
|
||||
domains.get(5).getRepoId(),
|
||||
"nsIp=5.5.5.1&cursor=ZG9tYWluNC5sb2w%3D",
|
||||
"rdap_domains_four_truncated.json");
|
||||
verifyMetrics(
|
||||
|
||||
@@ -248,4 +248,38 @@ class CopyDetailReportsActionTest {
|
||||
action.run();
|
||||
verifyNoInteractions(driveConnection);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_registrarIdWithUnderscores() throws IOException {
|
||||
persistResource(
|
||||
loadRegistrar("TheRegistrar")
|
||||
.asBuilder()
|
||||
.setRegistrarId("The_Registrar")
|
||||
.setDriveFolderId("0B-99999")
|
||||
.build());
|
||||
|
||||
gcsUtils.createFromBytes(
|
||||
BlobId.of("test-bucket", "results/invoice_details_2017-10_The_Registrar_test.csv"),
|
||||
"hello,world\n1,2".getBytes(UTF_8));
|
||||
|
||||
action.run();
|
||||
verify(driveConnection)
|
||||
.createOrUpdateFile(
|
||||
"invoice_details_2017-10_The_Registrar_test.csv",
|
||||
MediaType.CSV_UTF_8,
|
||||
"0B-99999",
|
||||
"hello,world\n1,2".getBytes(UTF_8));
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_invalidFilenamePattern_skipped() throws IOException {
|
||||
gcsUtils.createFromBytes(
|
||||
BlobId.of("test-bucket", "results/invoice_details_2017-10.csv"),
|
||||
"hello,world\n1,2".getBytes(UTF_8));
|
||||
|
||||
action.run();
|
||||
verifyNoInteractions(driveConnection);
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,17 +18,21 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.request.JsonResponse.JSON_SAFETY_PREFIX;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link JsonResponse}. */
|
||||
class JsonResponseTest {
|
||||
|
||||
private static final Gson GSON = GsonUtils.provideGson();
|
||||
|
||||
private FakeResponse fakeResponse = new FakeResponse();
|
||||
private JsonResponse jsonResponse = new JsonResponse(fakeResponse);
|
||||
private JsonResponse jsonResponse = new JsonResponse(fakeResponse, GSON);
|
||||
|
||||
@Test
|
||||
void testSetStatus() {
|
||||
@@ -44,9 +48,8 @@ class JsonResponseTest {
|
||||
jsonResponse.setPayload(responseValues);
|
||||
String payload = fakeResponse.getPayload();
|
||||
assertThat(payload).startsWith(JSON_SAFETY_PREFIX);
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> responseMap = (Map<String, Object>)
|
||||
JSONValue.parse(payload.substring(JSON_SAFETY_PREFIX.length()));
|
||||
Map<String, Object> responseMap =
|
||||
GSON.fromJson(payload.substring(JSON_SAFETY_PREFIX.length()), new TypeToken<>() {});
|
||||
assertThat(responseMap).containsExactlyEntriesIn(responseValues);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,21 +19,26 @@ import static google.registry.request.RequestModule.provideJsonPayload;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.request.HttpException.BadRequestException;
|
||||
import google.registry.request.HttpException.UnsupportedMediaTypeException;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link RequestModule}. */
|
||||
final class RequestModuleTest {
|
||||
|
||||
private static final Gson GSON = GsonUtils.provideGson();
|
||||
|
||||
@Test
|
||||
void testProvideJsonPayload() {
|
||||
assertThat(provideJsonPayload(MediaType.JSON_UTF_8, "{\"k\":\"v\"}")).containsExactly("k", "v");
|
||||
assertThat(provideJsonPayload(MediaType.JSON_UTF_8, "{\"k\":\"v\"}", GSON))
|
||||
.containsExactly("k", "v");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProvideJsonPayload_contentTypeWithoutCharsetAllowed() {
|
||||
assertThat(provideJsonPayload(MediaType.JSON_UTF_8.withoutParameters(), "{\"k\":\"v\"}"))
|
||||
assertThat(provideJsonPayload(MediaType.JSON_UTF_8.withoutParameters(), "{\"k\":\"v\"}", GSON))
|
||||
.containsExactly("k", "v");
|
||||
}
|
||||
|
||||
@@ -41,14 +46,16 @@ final class RequestModuleTest {
|
||||
void testProvideJsonPayload_malformedInput_throws500() {
|
||||
BadRequestException thrown =
|
||||
assertThrows(
|
||||
BadRequestException.class, () -> provideJsonPayload(MediaType.JSON_UTF_8, "{\"k\":"));
|
||||
BadRequestException.class,
|
||||
() -> provideJsonPayload(MediaType.JSON_UTF_8, "{\"k\":", GSON));
|
||||
assertThat(thrown).hasMessageThat().contains("Malformed JSON");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProvideJsonPayload_emptyInput_throws500() {
|
||||
BadRequestException thrown =
|
||||
assertThrows(BadRequestException.class, () -> provideJsonPayload(MediaType.JSON_UTF_8, ""));
|
||||
assertThrows(
|
||||
BadRequestException.class, () -> provideJsonPayload(MediaType.JSON_UTF_8, "", GSON));
|
||||
assertThat(thrown).hasMessageThat().contains("Malformed JSON");
|
||||
}
|
||||
|
||||
@@ -56,13 +63,13 @@ final class RequestModuleTest {
|
||||
void testProvideJsonPayload_nonJsonContentType_throws415() {
|
||||
assertThrows(
|
||||
UnsupportedMediaTypeException.class,
|
||||
() -> provideJsonPayload(MediaType.PLAIN_TEXT_UTF_8, "{}"));
|
||||
() -> provideJsonPayload(MediaType.PLAIN_TEXT_UTF_8, "{}", GSON));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProvideJsonPayload_contentTypeWithWeirdParam_throws415() {
|
||||
assertThrows(
|
||||
UnsupportedMediaTypeException.class,
|
||||
() -> provideJsonPayload(MediaType.JSON_UTF_8.withParameter("omg", "handel"), "{}"));
|
||||
() -> provideJsonPayload(MediaType.JSON_UTF_8.withParameter("omg", "handel"), "{}", GSON));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,9 +52,8 @@ import google.registry.schema.registrar.RegistrarDaoTest;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.platform.runner.JUnitPlatform;
|
||||
import org.junit.platform.suite.api.SelectClasses;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.platform.suite.api.Suite;
|
||||
|
||||
/**
|
||||
* Groups all JPA entity tests in one suite for easy invocation. This suite is used for
|
||||
@@ -68,20 +67,8 @@ import org.junit.runner.RunWith;
|
||||
* <p>Note that with {@link JpaIntegrationWithCoverageExtension}, each method starts with an empty
|
||||
* database. Therefore, this is not the right place for verifying backwards data compatibility in
|
||||
* end-to-end functional tests.
|
||||
*
|
||||
* <p>As of April 2020, none of the before/after annotations ({@code BeforeClass} and {@code
|
||||
* AfterClass} in JUnit 4, or {@code BeforeAll} and {@code AfterAll} in JUnit5) work in a test suite
|
||||
* run with {@link JUnitPlatform the current JUnit 5 runner}. However, staying with the JUnit 4
|
||||
* runner would prevent any member tests from migrating to JUnit 5.
|
||||
*
|
||||
* <p>This class uses a hack to work with the current JUnit 5 runner. {@link BeforeSuiteTest} is
|
||||
* added to the front of the suite class list and invokes the suite's setup method, and {@link
|
||||
* AfterSuiteTest} is added to the tail of the suite class list and invokes the suite's teardown
|
||||
* method. This works because the member tests are run in the order they are declared (See {@code
|
||||
* org.junit.platform.engine.support.descriptor.AbstractTestDescriptor#addChild}). Should the
|
||||
* ordering changes in the future, we will only get false alarms.
|
||||
*/
|
||||
@RunWith(JUnitPlatform.class)
|
||||
@Suite
|
||||
@SelectClasses({
|
||||
// BeforeSuiteTest must be the first entry. See class javadoc for details.
|
||||
BeforeSuiteTest.class,
|
||||
|
||||
@@ -20,21 +20,25 @@ import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.security.JsonHttp.JSON_SAFETY_PREFIX;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Map;
|
||||
import org.json.simple.JSONValue;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
/**
|
||||
* Helper class for testing JSON RPC servlets.
|
||||
*/
|
||||
public final class JsonHttpTestUtils {
|
||||
|
||||
private static final Gson GSON = GsonUtils.provideGson();
|
||||
|
||||
/** Returns JSON payload for mocked result of {@code rsp.getReader()}. */
|
||||
public static BufferedReader createJsonPayload(Map<String, ?> object) {
|
||||
return createJsonPayload(JSONValue.toJSONString(object));
|
||||
return createJsonPayload(GSON.toJson(object));
|
||||
}
|
||||
|
||||
/** @see #createJsonPayload(Map) */
|
||||
@@ -58,10 +62,8 @@ public final class JsonHttpTestUtils {
|
||||
assertThat(jsonText).startsWith(JSON_SAFETY_PREFIX);
|
||||
jsonText = jsonText.substring(JSON_SAFETY_PREFIX.length());
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> json = (Map<String, Object>) JSONValue.parseWithException(jsonText);
|
||||
return json;
|
||||
} catch (ClassCastException | ParseException e) {
|
||||
return GSON.fromJson(jsonText, new TypeToken<>() {});
|
||||
} catch (ClassCastException | JsonSyntaxException e) {
|
||||
assertWithMessage("Bad JSON: %s\n%s", e.getMessage(), jsonText).fail();
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public final class RegistryTestServer {
|
||||
|
||||
public static final ImmutableMap<String, Path> RUNFILES =
|
||||
new ImmutableMap.Builder<String, Path>()
|
||||
.put("/console/*", PROJECT_ROOT.resolve("console-webapp/staged/dist"))
|
||||
.put("/console/*", PROJECT_ROOT.resolve("console-webapp/staged/dist/browser"))
|
||||
.build();
|
||||
|
||||
public static final ImmutableList<Route> ROUTES =
|
||||
|
||||
@@ -31,6 +31,8 @@ import jakarta.servlet.annotation.MultipartConfig;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -138,30 +140,39 @@ public final class TestServer {
|
||||
.callWithTimeout(
|
||||
() -> {
|
||||
server.stop();
|
||||
RegistryEnvironment.setIsInTestDriver(false);
|
||||
return null;
|
||||
},
|
||||
SHUTDOWN_TIMEOUT_MS,
|
||||
TimeUnit.MILLISECONDS);
|
||||
for (var dir : multiPartTmpDirs) {
|
||||
try {
|
||||
Files.delete(dir);
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throwIfUnchecked(e);
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
RegistryEnvironment.setIsInTestDriver(false);
|
||||
}
|
||||
for (var dir : multiPartTmpDirs) {
|
||||
try {
|
||||
Files.delete(dir);
|
||||
} catch (IOException e) {
|
||||
// Nothing we can do
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return ((ServerConnector) server.getConnectors()[0]).getLocalPort();
|
||||
}
|
||||
|
||||
/** Returns a URL that can be used to communicate with this server. */
|
||||
public URL getUrl(String path) {
|
||||
checkArgument(path.startsWith("/"), "Path must start with a slash: %s", path);
|
||||
try {
|
||||
return new URL(String.format("http://%s%s", urlAddress, path));
|
||||
} catch (MalformedURLException e) {
|
||||
int port = getPort();
|
||||
if (port <= 0) {
|
||||
port = urlAddress.getPortOrDefault(DEFAULT_PORT);
|
||||
}
|
||||
return new URI(String.format("http://%s:%d%s", urlAddress.getHost(), port, path)).toURL();
|
||||
} catch (MalformedURLException | URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,9 @@ import google.registry.model.billing.BillingCancellation;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingRecurrence;
|
||||
import google.registry.model.common.DnsRefreshRequest;
|
||||
import google.registry.model.common.FeatureFlag;
|
||||
import google.registry.model.common.FeatureFlag.FeatureName;
|
||||
import google.registry.model.common.FeatureFlag.FeatureStatus;
|
||||
import google.registry.model.console.GlobalRole;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.console.UserRoles;
|
||||
@@ -682,6 +685,32 @@ public final class DatabaseHelper {
|
||||
return newRegistrars.build();
|
||||
}
|
||||
|
||||
/** Persists and returns a {@link FeatureFlag} with a single status starting from the epoch. */
|
||||
public static FeatureFlag persistFeatureFlag(FeatureName featureName, FeatureStatus status) {
|
||||
return persistFeatureFlag(featureName, ImmutableSortedMap.of(START_INSTANT, status));
|
||||
}
|
||||
|
||||
/** Persists and returns a {@link FeatureFlag} with an initial status and one transition. */
|
||||
public static FeatureFlag persistFeatureFlag(
|
||||
FeatureName featureName,
|
||||
FeatureStatus initialStatus,
|
||||
Instant transitionTime,
|
||||
FeatureStatus status) {
|
||||
return persistFeatureFlag(
|
||||
featureName,
|
||||
ImmutableSortedMap.<Instant, FeatureStatus>naturalOrder()
|
||||
.put(START_INSTANT, initialStatus)
|
||||
.put(transitionTime, status)
|
||||
.build());
|
||||
}
|
||||
|
||||
/** Persists and returns a {@link FeatureFlag} with a custom status map. */
|
||||
public static FeatureFlag persistFeatureFlag(
|
||||
FeatureName featureName, ImmutableSortedMap<Instant, FeatureStatus> statusMap) {
|
||||
return persistResource(
|
||||
new FeatureFlag.Builder().setFeatureName(featureName).setStatusMap(statusMap).build());
|
||||
}
|
||||
|
||||
public static Iterable<BillingBase> getBillingEvents() {
|
||||
return tm().transact(
|
||||
() ->
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package google.registry.testing;
|
||||
|
||||
import google.registry.request.JsonResponse;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import java.util.Map;
|
||||
|
||||
/** Fake implementation of {@link JsonResponse} for testing. */
|
||||
@@ -23,7 +24,7 @@ public final class FakeJsonResponse extends JsonResponse {
|
||||
private Map<String, ?> responseMap;
|
||||
|
||||
public FakeJsonResponse() {
|
||||
super(new FakeResponse());
|
||||
super(new FakeResponse(), GsonUtils.provideGson());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -19,7 +19,7 @@ import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATAS
|
||||
import static google.registry.model.common.FeatureFlag.FeatureName.TEST_FEATURE;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureStatus.ACTIVE;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureStatus.INACTIVE;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.DatabaseHelper.persistFeatureFlag;
|
||||
import static google.registry.util.DateTimeUtils.START_INSTANT;
|
||||
import static google.registry.util.DateTimeUtils.plusWeeks;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
@@ -27,7 +27,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import google.registry.model.common.FeatureFlag;
|
||||
import google.registry.model.common.FeatureFlag.FeatureStatus;
|
||||
import google.registry.model.common.TimedTransitionProperty;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.time.Instant;
|
||||
@@ -81,14 +80,7 @@ public class ConfigureFeatureFlagCommandTest extends CommandTestCase<ConfigureFe
|
||||
|
||||
@Test
|
||||
void testUpdate() throws Exception {
|
||||
persistResource(
|
||||
new FeatureFlag.Builder()
|
||||
.setFeatureName(TEST_FEATURE)
|
||||
.setStatusMap(
|
||||
ImmutableSortedMap.<Instant, FeatureStatus>naturalOrder()
|
||||
.put(START_INSTANT, INACTIVE)
|
||||
.build())
|
||||
.build());
|
||||
persistFeatureFlag(TEST_FEATURE, INACTIVE);
|
||||
|
||||
Instant featureStart = plusWeeks(clock.now(), 6);
|
||||
assertThat(FeatureFlag.get(TEST_FEATURE).getStatusMap())
|
||||
@@ -110,14 +102,7 @@ public class ConfigureFeatureFlagCommandTest extends CommandTestCase<ConfigureFe
|
||||
|
||||
@Test
|
||||
void testConfigure_multipleFlags() throws Exception {
|
||||
persistResource(
|
||||
new FeatureFlag.Builder()
|
||||
.setFeatureName(TEST_FEATURE)
|
||||
.setStatusMap(
|
||||
ImmutableSortedMap.<Instant, FeatureStatus>naturalOrder()
|
||||
.put(START_INSTANT, INACTIVE)
|
||||
.build())
|
||||
.build());
|
||||
persistFeatureFlag(TEST_FEATURE, INACTIVE);
|
||||
|
||||
Instant featureStart = plusWeeks(clock.now(), 6);
|
||||
assertThat(FeatureFlag.get(TEST_FEATURE).getStatusMap())
|
||||
@@ -179,14 +164,7 @@ public class ConfigureFeatureFlagCommandTest extends CommandTestCase<ConfigureFe
|
||||
|
||||
@Test
|
||||
void testUpdate_invalidStatusMap() throws Exception {
|
||||
persistResource(
|
||||
new FeatureFlag.Builder()
|
||||
.setFeatureName(TEST_FEATURE)
|
||||
.setStatusMap(
|
||||
ImmutableSortedMap.<Instant, FeatureStatus>naturalOrder()
|
||||
.put(START_INSTANT, INACTIVE)
|
||||
.build())
|
||||
.build());
|
||||
persistFeatureFlag(TEST_FEATURE, INACTIVE);
|
||||
|
||||
Instant featureStart = plusWeeks(clock.now(), 6);
|
||||
assertThat(FeatureFlag.get(TEST_FEATURE).getStatusMap())
|
||||
|
||||
@@ -15,8 +15,10 @@
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureName.FORBID_INSECURE_ALGORITHMS_RFC_9904;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.persistFeatureFlag;
|
||||
import static google.registry.testing.DatabaseHelper.persistPremiumList;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static org.joda.money.CurrencyUnit.JPY;
|
||||
@@ -25,6 +27,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import com.beust.jcommander.ParameterException;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.dns.writer.VoidDnsWriter;
|
||||
import google.registry.model.common.FeatureFlag.FeatureStatus;
|
||||
import google.registry.model.pricing.StaticPremiumListPricingEngine;
|
||||
import google.registry.model.tld.Tld;
|
||||
import google.registry.model.tld.label.PremiumListDao;
|
||||
@@ -49,9 +52,9 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
|
||||
"--period=1",
|
||||
"--nameservers=ns1.zdns.google,ns2.zdns.google,ns3.zdns.google,ns4.zdns.google",
|
||||
"--password=2fooBAR",
|
||||
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 5 1"
|
||||
+ " A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
|
||||
"--ds_records=60485 5 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 8 2"
|
||||
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"--ds_records=60485 8 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"example.tld");
|
||||
eppVerifier.verifySent("domain_create_complete.xml");
|
||||
}
|
||||
@@ -63,9 +66,9 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
|
||||
"--period=1",
|
||||
"--nameservers=NS1.zdns.google,ns2.ZDNS.google,ns3.zdns.gOOglE,ns4.zdns.google",
|
||||
"--password=2fooBAR",
|
||||
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 5 1"
|
||||
+ " A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
|
||||
"--ds_records=60485 5 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 8 2"
|
||||
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"--ds_records=60485 8 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"example.tld");
|
||||
eppVerifier.verifySent("domain_create_complete.xml");
|
||||
}
|
||||
@@ -77,9 +80,9 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
|
||||
"--period=1",
|
||||
"--nameservers=ns[1-4].zdns.google",
|
||||
"--password=2fooBAR",
|
||||
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 5 1"
|
||||
+ " A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
|
||||
"--ds_records=60485 5 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 8 2"
|
||||
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"--ds_records=60485 8 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"example.tld");
|
||||
eppVerifier.verifySent("domain_create_complete.xml");
|
||||
}
|
||||
@@ -91,9 +94,9 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
|
||||
"--period=1",
|
||||
"--nameservers=NS[1-4].zdns.google",
|
||||
"--password=2fooBAR",
|
||||
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 5 1"
|
||||
+ " A94A8FE5CCB19BA61C4C0873D391E987982FBBD3",
|
||||
"--ds_records=60485 5 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"--ds_records=1 2 2 9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08,4 8 2"
|
||||
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"--ds_records=60485 8 2 D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"example.tld");
|
||||
eppVerifier.verifySent("domain_create_complete.xml");
|
||||
}
|
||||
@@ -280,15 +283,28 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_invalidDigestLength() {
|
||||
void testFailure_forbiddenAlgorithm() {
|
||||
persistFeatureFlag(FORBID_INSECURE_ALGORITHMS_RFC_9904, FeatureStatus.ACTIVE);
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
runCommandForced(
|
||||
"--client=NewRegistrar",
|
||||
"--ds_records=1 2 1 abcd",
|
||||
"--ds_records=1 1 2"
|
||||
+ " D4B7D520E7BB5F0F67674A0CCEB1E3E0614B93C4F9E99B8383F6A1E4469DA50A",
|
||||
"example.tld"));
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("DS record uses an unrecognized algorithm: 1");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_invalidDigestLength() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
runCommandForced(
|
||||
"--client=NewRegistrar", "--ds_records=1 2 2 abcd", "example.tld"));
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("DS record has an invalid digest length: ABCD");
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,8 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureName.TEST_FEATURE;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureStatus.ACTIVE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.START_INSTANT;
|
||||
import static google.registry.testing.DatabaseHelper.persistFeatureFlag;
|
||||
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import google.registry.model.common.FeatureFlag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -30,12 +28,7 @@ public class DeleteFeatureFlagCommandTest extends CommandTestCase<DeleteFeatureF
|
||||
|
||||
@Test
|
||||
void testSimpleSuccess() throws Exception {
|
||||
persistResource(
|
||||
new FeatureFlag()
|
||||
.asBuilder()
|
||||
.setFeatureName(TEST_FEATURE)
|
||||
.setStatusMap(ImmutableSortedMap.of(START_INSTANT, ACTIVE))
|
||||
.build());
|
||||
persistFeatureFlag(TEST_FEATURE, ACTIVE);
|
||||
assertThat(tm().transact(() -> FeatureFlag.isActiveNow(TEST_FEATURE))).isTrue();
|
||||
runCommandForced("TEST_FEATURE");
|
||||
assertThat(FeatureFlag.getUncached(TEST_FEATURE)).isEmpty();
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2026 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link DigestType}. */
|
||||
class DigestTypeTest {
|
||||
|
||||
@Test
|
||||
void testFromWireValue_sha1_returnsSha1() {
|
||||
assertThat(DigestType.fromWireValue(1)).hasValue(DigestType.SHA1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFromWireValue_sha256_returnsSha256() {
|
||||
assertThat(DigestType.fromWireValue(2)).hasValue(DigestType.SHA256);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFromWireValue_gost_returnsEmpty() {
|
||||
assertThat(DigestType.fromWireValue(3)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFromWireValue_sha384_returnsSha384() {
|
||||
assertThat(DigestType.fromWireValue(4)).hasValue(DigestType.SHA384);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFromWireValue_invalid_returnsEmpty() {
|
||||
assertThat(DigestType.fromWireValue(5)).isEmpty();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user