Skip to content

Commit

Permalink
pushing new structure
Browse files Browse the repository at this point in the history
  • Loading branch information
Luthan95 committed Dec 16, 2021
1 parent 69e41af commit 132f37c
Show file tree
Hide file tree
Showing 107 changed files with 11,003 additions and 2 deletions.
Binary file added .gradle/6.8/executionHistory/executionHistory.bin
Binary file not shown.
Binary file added .gradle/6.8/executionHistory/executionHistory.lock
Binary file not shown.
Binary file added .gradle/6.8/fileChanges/last-build.bin
Binary file not shown.
Binary file added .gradle/6.8/fileHashes/fileHashes.bin
Binary file not shown.
Binary file added .gradle/6.8/fileHashes/fileHashes.lock
Binary file not shown.
Empty file added .gradle/6.8/gc.properties
Empty file.
Binary file added .gradle/buildOutputCleanup/buildOutputCleanup.lock
Binary file not shown.
2 changes: 2 additions & 0 deletions .gradle/buildOutputCleanup/cache.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#Thu Dec 16 10:22:57 IST 2021
gradle.version=6.8
Binary file added .gradle/buildOutputCleanup/outputFiles.bin
Binary file not shown.
Binary file added .gradle/checksums/checksums.lock
Binary file not shown.
Empty file.
Empty file added .gradle/vcs-1/gc.properties
Empty file.
3 changes: 3 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions front50/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
build
.gradle
.idea
node_modules
.DS_Store
1 change: 1 addition & 0 deletions front50/.husky/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_
9 changes: 9 additions & 0 deletions front50/.husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# CHECK THIS FILE INTO SOURCE CONTROL!

. "$(dirname "$0")/_/husky.sh"

if [[ -e custom-stage-deck/node_modules/.bin/lint-staged ]]; then
cd custom-stage-deck;
./node_modules/.bin/lint-staged -p false
fi
53 changes: 53 additions & 0 deletions front50/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
buildscript {
repositories {
mavenCentral()
}
}

plugins {
id("io.spinnaker.plugin.bundler").version("$spinnakerGradleVersion")
id("com.palantir.git-version").version("0.12.2")
id("com.diffplug.spotless").version("5.1.0")
}

repositories {
mavenCentral()
}

spinnakerBundle {
pluginId = "Opsmx.StaticPolicyPlugin"
description = "An example of a PF4J-based plugin that provides a custom pipeline stage."
provider = "https://github.com/opsmx"
version = rootProject.version
}

version = "v1.0.1"

subprojects {
group = "com.opsmx.plugin.stage.custom"
version = rootProject.version

if (name != "custom-stage-deck") {
apply plugin: "com.diffplug.spotless"
spotless {
kotlin {
ktlint().userData([
disabled_rules : "no-wildcard-imports",
indent_size : "2",
continuation_indent_size: "2",
])
}
}
}
}

String normalizedVersion() {
String fullVersion = gitVersion()
String normalized = fullVersion.split("-").first()
if (fullVersion.contains("dirty")) {
return "$normalized-SNAPSHOT"
} else {
return normalized
}
}

89 changes: 89 additions & 0 deletions front50/custom-stage-front50/custom-stage-front50.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import org.yaml.snakeyaml.Yaml

buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion"
}
}

apply plugin: "io.spinnaker.plugin.service-extension"
apply plugin: "maven-publish"
apply plugin: "kotlin"
apply plugin: "kotlin-kapt"
apply plugin: "kotlin-spring"

repositories {
mavenCentral()
jcenter()
maven { url "https://spinnaker-releases.bintray.com/jars" }
}

sourceSets {
main {
java { srcDirs = ['src/main/java'] }
}
}

spinnakerPlugin {
serviceName = "front50"
pluginClass = "com.opsmx.plugin.stage.custom.StaticPolicyPlugin"
requires="front50>=0.0.0"
}
configurations {
// configuration that holds jars to include in the jar
extraLibs
}

dependencies {
compileOnly "org.pf4j:pf4j:${pf4jVersion}"
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
compileOnly "com.netflix.spinnaker.kork:kork-plugins-api:${korkVersion}"
compileOnly 'com.netflix.spinnaker.kork:kork-web:7.105.0'
kapt "org.pf4j:pf4j:${pf4jVersion}"

compileOnly group: 'com.squareup.retrofit', name: 'retrofit', version: '1.9.0'
compileOnly group: 'com.squareup.retrofit', name: 'converter-jackson', version: '1.9.0'
compileOnly group: 'com.jakewharton.retrofit', name: 'retrofit1-okhttp3-client', version: '1.1.0'
implementation group: 'com.jcraft', name: 'jsch', version: '0.1.55'

/*testImplementation "com.netflix.spinnaker.kork:kork-plugins-tck"
testImplementation(platform("io.spinnaker.front50:front50-bom:2.24.0"))
testImplementation "org.junit.jupiter:junit-jupiter-api:5.5.2"
testImplementation "io.strikt:strikt-core:0.22.1"
testImplementation "dev.minutest:minutest:1.10.0"
testImplementation "io.mockk:mockk:1.9.3"
testImplementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.11.1"
testImplementation "javax.servlet:javax.servlet-api:4.0.1"*/

testRuntime "org.junit.jupiter:junit-jupiter-engine:5.4.0"
testRuntime "org.junit.platform:junit-platform-launcher:1.4.0"
testRuntime "org.junit.platform:junit-platform-commons:1.5.2"
implementation("org.apache.commons:commons-lang3:3.0")

implementation 'com.google.code.gson:gson:2.8.8'
extraLibs group: 'com.netflix.spinnaker.front50', name: 'front50-core', version: '2.23.0'
configurations.compile.extendsFrom(configurations.extraLibs)
}

configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'org.apache.logging.log4j') {
details.useVersion '2.16.0'
}
}
}

jar {
from {
configurations.extraLibs.collect { it.isDirectory() ? it : zipTree(it) }
}
}

tasks.withType(Test) {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package com.opsmx.plugin.stage.custom;

import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.pf4j.Extension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.netflix.spinnaker.front50.ApplicationPermissionsService;
import com.netflix.spinnaker.front50.model.application.Application;
import com.netflix.spinnaker.front50.validator.ApplicationValidationErrors;
import com.netflix.spinnaker.front50.validator.ApplicationValidator;
import com.netflix.spinnaker.kork.plugins.api.internal.SpinnakerExtensionPoint;
import com.netflix.spinnaker.kork.web.exceptions.ValidationException;

import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

@Extension
@Component
public class ApplicationNameValidation implements ApplicationValidator, SpinnakerExtensionPoint {

private final Logger logger = LoggerFactory.getLogger(ApplicationNameValidation.class);

@Value("${policy.opa.url:http://oes-server-svc.oes:8085}")
private String opaUrl;

@Value("${policy.opa.resultKey:deny}")
private String opaResultKey;

@Value("${policy.opa.policyLocation:/v1/staticPolicy/eval}")
private String opaPolicyLocation;

@Value("${policy.opa.enabled:false}")
private boolean isOpaEnabled;

@Value("${policy.opa.proxy:true}")
private boolean isOpaProxy;

@Value("${policy.opa.deltaVerification:false}")
private boolean deltaVerification;

private final Gson gson = new Gson();

/* OPA spits JSON */
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private final OkHttpClient opaClient = new OkHttpClient();

@Override
public void validate(Application application, ApplicationValidationErrors validationErrors) {
if (!isOpaEnabled) {
logger.info("OPA not enabled, returning");
return;
}
String finalInput = null;
Response httpResponse;
try {
finalInput = getOpaInput(application);
logger.debug("Verifying {} with OPA", finalInput);

RequestBody requestBody = RequestBody.create(JSON, finalInput);
String opaFinalUrl = String.format("%s/%s", opaUrl.endsWith("/") ? opaUrl.substring(0, opaUrl.length() - 1) : opaUrl, opaPolicyLocation.startsWith("/") ? opaPolicyLocation.substring(1) : opaPolicyLocation);

logger.debug("OPA endpoint : {}", opaFinalUrl);
String opaStringResponse;

/* fetch the response from the spawned call execution */
httpResponse = doPost(opaFinalUrl, requestBody);
opaStringResponse = httpResponse.body().string();
logger.info("OPA response: {}", opaStringResponse);
if (isOpaProxy) {
if (httpResponse.code() == 401 ) {
JsonObject opaResponse = gson.fromJson(opaStringResponse, JsonObject.class);
StringBuilder denyMessage = new StringBuilder();
extractDenyMessage(opaResponse, denyMessage);
String opaMessage = denyMessage.toString();
if (StringUtils.isNotBlank(opaMessage)) {
validationErrors.rejectValue(
"name",
"application.name.invalid with opa deny",
Optional.ofNullable(opaMessage)
.orElse("Application doesn't satisfy the policy specified"));
} else {
validationErrors.rejectValue(
"name",
"application.name.invalid","Application doesn't satisfy the policy specified");
}
} else if (httpResponse.code() != 200 ) {
validationErrors.rejectValue(
"name",
"application.name.invalid", httpResponse.message());;
}
}

} catch (Exception e) {
logger.error("Communication exception for OPA at {}: {}", this.opaUrl, e.toString());
validationErrors.rejectValue(
"name",
"application.name.invalid", e.toString());
}
}

private void extractDenyMessage(JsonObject opaResponse, StringBuilder messagebuilder) {
Set<Entry<String, JsonElement>> fields = opaResponse.entrySet();
fields.forEach(field -> {
if (field.getKey().equalsIgnoreCase(opaResultKey)) {
JsonArray resultKey = field.getValue().getAsJsonArray();
if (resultKey.size() != 0) {
resultKey.forEach(result -> {
if (StringUtils.isNotEmpty(messagebuilder)) {
messagebuilder.append(", ");
}
messagebuilder.append(result.getAsString());
});
}
}else if (field.getValue().isJsonObject()) {
extractDenyMessage(field.getValue().getAsJsonObject(), messagebuilder);
} else if (field.getValue().isJsonArray()){
field.getValue().getAsJsonArray().forEach(obj -> {
extractDenyMessage(obj.getAsJsonObject(), messagebuilder);
});
}
});
}


private String getOpaInput(Application application) {

JsonObject applicationJson = pipelineToJsonObject(application);

String finalInput = gson.toJson(addWrapper(addWrapper(applicationJson, "app"), "input"));
return finalInput;
}

private JsonObject pipelineToJsonObject(Application application) {
String applicationStr = gson.toJson(application, Application.class);
return gson.fromJson(applicationStr, JsonObject.class);
}

private JsonObject addWrapper(JsonObject pipeline, String wrapper) {
JsonObject input = new JsonObject();
input.add(wrapper, pipeline);
return input;
}

private Response doPost(String url, RequestBody requestBody) throws IOException {
Request req = (new Request.Builder()).url(url).post(requestBody).build();
return getResponse(url, req);
}

private Response getResponse(String url, Request req) throws IOException {
Response httpResponse = this.opaClient.newCall(req).execute();
ResponseBody responseBody = httpResponse.body();
if (responseBody == null) {
throw new IOException("Http call yielded null response!! url:" + url);
}
return httpResponse;
}
}
Loading

0 comments on commit 132f37c

Please sign in to comment.