mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-12 19:32:48 -06:00
website: Display 2025 survey results on the website (#8258)
* Add survey data * Add survey results pages with recharts for plots Some simple cross year comparisons have been added too where data was available for the inspection of trends. Signed-off-by: Charlie Egan <charlie_egan@apple.com>
This commit is contained in:
@@ -7,6 +7,7 @@ const path = require("path");
|
||||
|
||||
import { loadPages } from "./src/lib/ecosystem/loadPages.js";
|
||||
import { loadRules } from "./src/lib/projects/regal/loadRules.js";
|
||||
import { loadSurveyEventData, loadSurveyQuestions, loadSurveyEventMetadata } from "./src/lib/surveys/loadSurveyData.js";
|
||||
|
||||
const baseUrl = "/";
|
||||
|
||||
@@ -132,6 +133,7 @@ const baseUrl = "/";
|
||||
{ to: "/security", label: "Security" },
|
||||
{ to: "/support", label: "Support" },
|
||||
{ to: "/community", label: "Community" },
|
||||
{ to: "/survey", label: "Survey" },
|
||||
{ href: "https://blog.openpolicyagent.org/", label: "Blog" },
|
||||
],
|
||||
},
|
||||
@@ -536,6 +538,50 @@ The Linux Foundation has registered trademarks and uses trademarks. For a list o
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async function surveyData(context, options) {
|
||||
return {
|
||||
name: "survey-data",
|
||||
|
||||
async loadContent() {
|
||||
const eventData = await loadSurveyEventData(
|
||||
path.join(context.siteDir, "src/data/surveys/events/**/**/data.json")
|
||||
);
|
||||
const questions = await loadSurveyQuestions(
|
||||
path.join(context.siteDir, "src/data/surveys/questions/**/data.json")
|
||||
);
|
||||
const eventMetadata = await loadSurveyEventMetadata(
|
||||
path.join(context.siteDir, "src/data/surveys/events/**/metadata.json")
|
||||
);
|
||||
|
||||
return { eventData, questions, eventMetadata };
|
||||
},
|
||||
|
||||
async contentLoaded({ content, actions }) {
|
||||
const { createData, addRoute } = actions;
|
||||
const { eventData, questions, eventMetadata } = content;
|
||||
|
||||
await createData("survey-event-data.json", JSON.stringify(eventData, null, 2));
|
||||
await createData("survey-questions.json", JSON.stringify(questions, null, 2));
|
||||
await createData("survey-event-metadata.json", JSON.stringify(eventMetadata, null, 2));
|
||||
|
||||
// Create a page for each event
|
||||
const eventSlugs = Object.keys(eventData);
|
||||
await Promise.all(
|
||||
eventSlugs.map(async (eventSlug) => {
|
||||
const routePath = path.join(baseUrl, `/survey/${eventSlug}`);
|
||||
return addRoute({
|
||||
path: routePath,
|
||||
component: require.resolve("./src/SurveyEvent/index.js"),
|
||||
exact: true,
|
||||
modules: {},
|
||||
customData: { eventSlug },
|
||||
});
|
||||
}),
|
||||
);
|
||||
},
|
||||
};
|
||||
},
|
||||
],
|
||||
clientModules: [
|
||||
require.resolve("./src/lib/playground.js"),
|
||||
|
||||
Generated
+215
-5
@@ -20,7 +20,8 @@
|
||||
"glob": "^11.0.3",
|
||||
"md-front-matter": "^1.0.4",
|
||||
"raw-loader": "^4.0.2",
|
||||
"react-markdown": "^10.1.0"
|
||||
"react-markdown": "^10.1.0",
|
||||
"recharts": "3.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.0.0"
|
||||
@@ -232,6 +233,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.41.0.tgz",
|
||||
"integrity": "sha512-G9I2atg1ShtFp0t7zwleP6aPS4DcZvsV4uoQOripp16aR6VJzbEnKFPLW4OFXzX7avgZSpYeBAS+Zx4FOgmpPw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/client-common": "5.41.0",
|
||||
"@algolia/requester-browser-xhr": "5.41.0",
|
||||
@@ -392,6 +394,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz",
|
||||
"integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.26.2",
|
||||
@@ -2214,6 +2217,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
@@ -2236,6 +2240,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -2345,6 +2350,7 @@
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
|
||||
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
@@ -2766,6 +2772,7 @@
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
|
||||
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
@@ -3629,6 +3636,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.9.2.tgz",
|
||||
"integrity": "sha512-C5wZsGuKTY8jEYsqdxhhFOe1ZDjH0uIYJ9T/jebHwkyxqnr4wW0jTkB72OMqNjsoQRcb0JN3PcSeTwFlVgzCZg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "3.9.2",
|
||||
"@docusaurus/logger": "3.9.2",
|
||||
@@ -3897,6 +3905,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-3.9.2.tgz",
|
||||
"integrity": "sha512-6c4DAbR6n6nPbnZhY2V3tzpnKnGL+6aOsLvFL26VRqhlczli9eWG0VDUNoCQEPnGwDMhPS42UhSAnz5pThm5Ag==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@docusaurus/mdx-loader": "3.9.2",
|
||||
"@docusaurus/module-type-aliases": "3.9.2",
|
||||
@@ -4600,6 +4609,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.0.tgz",
|
||||
"integrity": "sha512-QjHtSaoameoalGnKDT3FoIl4+9RwyTmo9ZJGBdLOks/YOiWHoRDI3PUwEzOE7kEmGcV3AFcp9K6dYu9rEuKLAQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/mdx": "^2.0.0"
|
||||
},
|
||||
@@ -4617,6 +4627,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@mermaid-js/layout-elk/-/layout-elk-0.1.9.tgz",
|
||||
"integrity": "sha512-HuvaqFZBr6yT9PpWYockvKAZPJVd89yn/UjOYPxhzbZxlybL2v+2BjVCg7MVH6vRs1irUohb/s42HEdec1CCZw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"d3": "^7.9.0",
|
||||
"elkjs": "^0.9.3"
|
||||
@@ -4990,6 +5001,42 @@
|
||||
"integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@reduxjs/toolkit": {
|
||||
"version": "2.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz",
|
||||
"integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
"@standard-schema/utils": "^0.3.0",
|
||||
"immer": "^11.0.0",
|
||||
"redux": "^5.0.1",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"reselect": "^5.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
|
||||
"react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@reduxjs/toolkit/node_modules/immer": {
|
||||
"version": "11.1.3",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-11.1.3.tgz",
|
||||
"integrity": "sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/immer"
|
||||
}
|
||||
},
|
||||
"node_modules/@sideway/address": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
|
||||
@@ -5046,6 +5093,12 @@
|
||||
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@standard-schema/utils": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
|
||||
"integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@svgr/babel-plugin-add-jsx-attribute": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz",
|
||||
@@ -5205,6 +5258,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz",
|
||||
"integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.21.3",
|
||||
"@svgr/babel-preset": "8.1.0",
|
||||
@@ -5845,6 +5899,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz",
|
||||
"integrity": "sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
@@ -5948,6 +6003,12 @@
|
||||
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/use-sync-external-store": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
|
||||
"integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.18.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||
@@ -6193,6 +6254,7 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
|
||||
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -6266,6 +6328,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
@@ -6311,6 +6374,7 @@
|
||||
"resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.41.0.tgz",
|
||||
"integrity": "sha512-9E4b3rJmYbBkn7e3aAPt1as+VVnRhsR4qwRRgOzpeyz4PAOuwKh0HI4AN6mTrqK0S0M9fCCSTOUnuJ8gPY/tvA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@algolia/abtesting": "1.7.0",
|
||||
"@algolia/client-abtesting": "5.41.0",
|
||||
@@ -6821,6 +6885,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.3",
|
||||
"caniuse-lite": "^1.0.30001741",
|
||||
@@ -7120,6 +7185,7 @@
|
||||
"resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz",
|
||||
"integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@chevrotain/cst-dts-gen": "11.0.3",
|
||||
"@chevrotain/gast": "11.0.3",
|
||||
@@ -7818,6 +7884,7 @@
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
|
||||
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
@@ -8137,6 +8204,7 @@
|
||||
"resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.32.0.tgz",
|
||||
"integrity": "sha512-5JHBC9n75kz5851jeklCPmZWcg3hUe6sjqJvyk3+hVqFaKcHwHgxsjeN1yLmggoUc6STbtm9/NQyabQehfjvWQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
@@ -8558,6 +8626,7 @@
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
@@ -8681,6 +8750,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/decimal.js-light": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
|
||||
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/decode-named-character-reference": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz",
|
||||
@@ -9202,6 +9277,16 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-toolkit": {
|
||||
"version": "1.44.0",
|
||||
"resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.44.0.tgz",
|
||||
"integrity": "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"docs",
|
||||
"benchmarks"
|
||||
]
|
||||
},
|
||||
"node_modules/esast-util-from-estree": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz",
|
||||
@@ -9772,6 +9857,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
@@ -10985,6 +11071,16 @@
|
||||
"integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/immer": {
|
||||
"version": "10.2.0",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz",
|
||||
"integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/immer"
|
||||
}
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
|
||||
@@ -14570,6 +14666,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
@@ -15161,6 +15258,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
@@ -16064,6 +16162,7 @@
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
|
||||
"integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
@@ -16893,6 +16992,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
@@ -17012,7 +17112,8 @@
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/react-json-view-lite": {
|
||||
"version": "2.5.0",
|
||||
@@ -17032,6 +17133,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz",
|
||||
"integrity": "sha512-YMMxTUQV/QFSnbgrP3tjDzLHRg7vsbMn8e9HAa8o/1iXoiomo48b7sk/kkmWEuWNDPJVlKSJRB6Y2fHqdJk+SQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
},
|
||||
@@ -17082,11 +17184,36 @@
|
||||
"react": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/react-redux": {
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
||||
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/use-sync-external-store": "^0.0.6",
|
||||
"use-sync-external-store": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.2.25 || ^19",
|
||||
"react": "^18.0 || ^19",
|
||||
"redux": "^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "5.3.4",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz",
|
||||
"integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.13",
|
||||
"history": "^4.9.0",
|
||||
@@ -17159,6 +17286,42 @@
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/recharts": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/recharts/-/recharts-3.7.0.tgz",
|
||||
"integrity": "sha512-l2VCsy3XXeraxIID9fx23eCb6iCBsxUQDnE8tWm6DFdszVAO7WVY/ChAD9wVit01y6B2PMupYiMmQwhgPHc9Ew==",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"www"
|
||||
],
|
||||
"dependencies": {
|
||||
"@reduxjs/toolkit": "1.x.x || 2.x.x",
|
||||
"clsx": "^2.1.1",
|
||||
"decimal.js-light": "^2.5.1",
|
||||
"es-toolkit": "^1.39.3",
|
||||
"eventemitter3": "^5.0.1",
|
||||
"immer": "^10.1.1",
|
||||
"react-redux": "8.x.x || 9.x.x",
|
||||
"reselect": "5.1.1",
|
||||
"tiny-invariant": "^1.3.3",
|
||||
"use-sync-external-store": "^1.2.2",
|
||||
"victory-vendor": "^37.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/recharts/node_modules/eventemitter3": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz",
|
||||
"integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/recma-build-jsx": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz",
|
||||
@@ -17223,6 +17386,22 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/redux-thunk": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
|
||||
"integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"redux": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerate": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
||||
@@ -17629,6 +17808,12 @@
|
||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/reselect": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
|
||||
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.10",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||
@@ -17817,8 +18002,7 @@
|
||||
"version": "0.26.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz",
|
||||
"integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/schema-dts": {
|
||||
"version": "1.1.5",
|
||||
@@ -18953,7 +19137,8 @@
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
"license": "0BSD",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "2.19.0",
|
||||
@@ -19358,6 +19543,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
@@ -19528,6 +19714,28 @@
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/victory-vendor": {
|
||||
"version": "37.3.6",
|
||||
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz",
|
||||
"integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==",
|
||||
"license": "MIT AND ISC",
|
||||
"dependencies": {
|
||||
"@types/d3-array": "^3.0.3",
|
||||
"@types/d3-ease": "^3.0.0",
|
||||
"@types/d3-interpolate": "^3.0.1",
|
||||
"@types/d3-scale": "^4.0.2",
|
||||
"@types/d3-shape": "^3.1.0",
|
||||
"@types/d3-time": "^3.0.0",
|
||||
"@types/d3-timer": "^3.0.0",
|
||||
"d3-array": "^3.1.6",
|
||||
"d3-ease": "^3.0.1",
|
||||
"d3-interpolate": "^3.0.1",
|
||||
"d3-scale": "^4.0.2",
|
||||
"d3-shape": "^3.1.0",
|
||||
"d3-time": "^3.0.0",
|
||||
"d3-timer": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-jsonrpc": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
|
||||
@@ -19614,6 +19822,7 @@
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.5.tgz",
|
||||
"integrity": "sha512-q+vHBa6H9qwBLUlHL4Y7L0L1/LlyBKZtS9FHNCQmtayxjI5RKC9yD8gpvLeqGv5lCQp1Re04yi0MF40pf30Pvg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.7",
|
||||
"@types/estree": "^1.0.6",
|
||||
@@ -20269,6 +20478,7 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.12.tgz",
|
||||
"integrity": "sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
|
||||
+2
-1
@@ -21,7 +21,8 @@
|
||||
"glob": "^11.0.3",
|
||||
"md-front-matter": "^1.0.4",
|
||||
"raw-loader": "^4.0.2",
|
||||
"react-markdown": "^10.1.0"
|
||||
"react-markdown": "^10.1.0",
|
||||
"recharts": "3.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.0.0"
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
import React, { useMemo } from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import Heading from "@theme/Heading";
|
||||
import Link from "@docusaurus/Link";
|
||||
|
||||
import StandaloneLayout from "../components/StandaloneLayout";
|
||||
import QuestionSingle from "../components/QuestionSingle";
|
||||
|
||||
import allEventData from "@generated/survey-data/default/survey-event-data.json";
|
||||
import questions from "@generated/survey-data/default/survey-questions.json";
|
||||
import eventMetadata from "@generated/survey-data/default/survey-event-metadata.json";
|
||||
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
export default function SurveyEvent(props) {
|
||||
const { eventSlug } = props.route.customData;
|
||||
const eventData = allEventData[eventSlug];
|
||||
const metadata = eventMetadata[eventSlug];
|
||||
|
||||
if (!eventData) {
|
||||
return (
|
||||
<StandaloneLayout
|
||||
title={`Survey`}
|
||||
description={`Open Policy Agent Survey Results`}
|
||||
>
|
||||
<p>
|
||||
<Link to="/survey">← View all survey events</Link>
|
||||
</p>
|
||||
<Heading as="h1">Survey Results</Heading>
|
||||
<p>No survey data available for this event.</p>
|
||||
</StandaloneLayout>
|
||||
);
|
||||
}
|
||||
|
||||
const questionIds = Object.keys(eventData);
|
||||
const pageTitle = metadata?.title || `Survey Results`;
|
||||
|
||||
// Group questions by tags and sort by rank
|
||||
const groupedQuestions = useMemo(() => {
|
||||
const groups = questionIds.reduce((acc, questionId) => {
|
||||
const question = questions[questionId];
|
||||
const tag = question?.tags?.[0] || 'uncategorized';
|
||||
(acc[tag] = acc[tag] || []).push(questionId);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
Object.values(groups).forEach(group =>
|
||||
group.sort((a, b) => (questions[a]?.rank || 999) - (questions[b]?.rank || 999))
|
||||
);
|
||||
|
||||
return groups;
|
||||
}, [questionIds, questions]);
|
||||
|
||||
// Build tag metadata from metadata.sections
|
||||
const { tagOrder, tagDisplayNames, tagDescriptions } = useMemo(() => {
|
||||
const order = metadata?.sections?.map(s => s.tag) || Object.keys(groupedQuestions);
|
||||
const displayNames = {
|
||||
uncategorized: 'Other',
|
||||
...metadata?.sections?.reduce((acc, s) => ({ ...acc, [s.tag]: s.title }), {})
|
||||
};
|
||||
const descriptions = metadata?.sections?.reduce((acc, s) =>
|
||||
s.description ? { ...acc, [s.tag]: s.description } : acc
|
||||
, {}) || {};
|
||||
|
||||
return { tagOrder: order, tagDisplayNames: displayNames, tagDescriptions: descriptions };
|
||||
}, [metadata, groupedQuestions]);
|
||||
|
||||
// Generate TOC items from tag sections
|
||||
const tocItems = useMemo(() => {
|
||||
return tagOrder
|
||||
.filter(tag => {
|
||||
const questionsInGroup = groupedQuestions[tag];
|
||||
return questionsInGroup && questionsInGroup.length > 0;
|
||||
})
|
||||
.map(tag => ({
|
||||
value: tagDisplayNames[tag] || tag,
|
||||
id: tag,
|
||||
level: 2,
|
||||
}));
|
||||
}, [tagOrder, groupedQuestions, tagDisplayNames]);
|
||||
|
||||
return (
|
||||
<StandaloneLayout
|
||||
title={metadata?.title || `Survey`}
|
||||
description={metadata?.title || `Open Policy Agent Survey Results`}
|
||||
toc={tocItems}
|
||||
>
|
||||
<p>
|
||||
<Link to="/survey">← View all survey events</Link>
|
||||
</p>
|
||||
<Heading as="h1">{pageTitle}</Heading>
|
||||
|
||||
{metadata?.intro && (
|
||||
<p>
|
||||
{metadata.intro}
|
||||
{metadata?.blog && (
|
||||
<>
|
||||
{" "}These results were originally presented in the following{" "}
|
||||
<Link to={metadata.blog}>blog post</Link>.
|
||||
</>
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{tagOrder.map(tag => {
|
||||
const questionsInGroup = groupedQuestions[tag];
|
||||
if (!questionsInGroup || questionsInGroup.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const displayName = tagDisplayNames[tag] || tag;
|
||||
const description = tagDescriptions[tag];
|
||||
|
||||
return (
|
||||
<div key={tag} className={styles.tagSection}>
|
||||
<Heading as="h2" id={tag} className={styles.tagHeading}>
|
||||
{displayName}
|
||||
</Heading>
|
||||
{description && (
|
||||
<div className={styles.tagDescription}>
|
||||
<ReactMarkdown>{description}</ReactMarkdown>
|
||||
</div>
|
||||
)}
|
||||
{questionsInGroup.map(questionId => (
|
||||
<QuestionSingle
|
||||
key={questionId}
|
||||
question={questions[questionId]}
|
||||
eventData={eventData[questionId]}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</StandaloneLayout>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
.tagSection {
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
.tagHeading {
|
||||
margin-top: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.tagDescription {
|
||||
margin-bottom: 2rem;
|
||||
color: var(--ifm-color-emphasis-700);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import React from 'react';
|
||||
import Heading from '@theme/Heading';
|
||||
|
||||
import { getChartComponent } from '../charts';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
||||
export default function QuestionComparison({
|
||||
questionId,
|
||||
question,
|
||||
eventData,
|
||||
eventSlugs,
|
||||
eventMetadata,
|
||||
}) {
|
||||
const ChartComponent = getChartComponent(question.comparisonChartType);
|
||||
|
||||
const chartData = eventSlugs.map(eventSlug => {
|
||||
const eventQuestionData = eventData[eventSlug][questionId];
|
||||
if (!eventQuestionData || !eventQuestionData.data) return null;
|
||||
|
||||
const displayName = eventMetadata[eventSlug]?.year?.toString() || eventSlug;
|
||||
const dataPoint = { name: displayName };
|
||||
|
||||
eventQuestionData.data.forEach(item => {
|
||||
dataPoint[item.label] = item.value;
|
||||
});
|
||||
|
||||
return dataPoint;
|
||||
}).filter(Boolean);
|
||||
|
||||
const allCategories = eventSlugs.flatMap(eventSlug => {
|
||||
const eventQuestionData = eventData[eventSlug][questionId];
|
||||
return (eventQuestionData && eventQuestionData.data) ? eventQuestionData.data.map(item => item.label) : [];
|
||||
});
|
||||
const categories = Array.from(new Set(allCategories));
|
||||
|
||||
const allFootnotes = eventSlugs.flatMap(eventSlug => {
|
||||
const eventQuestionData = eventData[eventSlug][questionId];
|
||||
if (!eventQuestionData || !eventQuestionData.footnotes || eventQuestionData.footnotes.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const year = eventMetadata[eventSlug]?.year?.toString() || eventSlug;
|
||||
return eventQuestionData.footnotes.map(footnote => `${year}: ${footnote}`);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Heading as="h3">{question.title}</Heading>
|
||||
{ChartComponent && (
|
||||
<ChartComponent
|
||||
data={chartData}
|
||||
config={question.chartConfig}
|
||||
categories={categories}
|
||||
/>
|
||||
)}
|
||||
{allFootnotes.length > 0 && (
|
||||
<div className={styles.footnotesContainer}>
|
||||
{allFootnotes.map((footnote, index) => (
|
||||
<p key={index} className={styles.footnote}>
|
||||
{footnote}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
.container {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.footnotesContainer {
|
||||
font-size: 0.85em;
|
||||
color: var(--ifm-color-emphasis-700);
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.footnote {
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
import React from 'react';
|
||||
import Heading from '@theme/Heading';
|
||||
|
||||
import { getChartComponent } from '../charts';
|
||||
|
||||
import styles from './styles.module.css';
|
||||
|
||||
export default function QuestionSingle({
|
||||
question,
|
||||
eventData,
|
||||
}) {
|
||||
if (!question || !eventData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const ChartComponent = getChartComponent(question.chartType);
|
||||
|
||||
if (question.chartType === 'text-list') {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Heading as="h3">{question.title}</Heading>
|
||||
{ChartComponent && (
|
||||
<ChartComponent
|
||||
intro={eventData.intro}
|
||||
bullets={eventData.bullets}
|
||||
config={question.chartConfig}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const chartData = eventData.data.map(item => ({
|
||||
name: item.label,
|
||||
value: item.value
|
||||
}));
|
||||
|
||||
const categories = [];
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Heading as="h3">{question.title}</Heading>
|
||||
{ChartComponent && (
|
||||
<ChartComponent
|
||||
data={chartData}
|
||||
config={question.chartConfig}
|
||||
categories={categories}
|
||||
/>
|
||||
)}
|
||||
{eventData.footnotes && eventData.footnotes.length > 0 && (
|
||||
<div className={styles.footnotesContainer}>
|
||||
{eventData.footnotes.map((footnote, index) => (
|
||||
<p key={index} className={styles.footnote}>
|
||||
{footnote}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
.container {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.footnotesContainer {
|
||||
font-size: 0.85em;
|
||||
color: var(--ifm-color-emphasis-700);
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.footnote {
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
import React from "react";
|
||||
// Using clsx to conditionally apply Docusaurus global styles
|
||||
import clsx from "clsx";
|
||||
|
||||
import { useWindowSize } from "@docusaurus/theme-common";
|
||||
import Layout from "@theme/Layout";
|
||||
import TOC from "@theme/TOC";
|
||||
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
@@ -8,18 +12,39 @@ import styles from "./styles.module.css";
|
||||
* A layout component that replicates the styling of a standard MDX page.
|
||||
* This is used to maintain consistent styling with mdx pages like security.
|
||||
*/
|
||||
export default function StandaloneLayout({ title, description, children }) {
|
||||
export default function StandaloneLayout({ title, description, children, toc = null }) {
|
||||
const windowSize = useWindowSize();
|
||||
|
||||
// Determine if we should show the TOC
|
||||
const canRenderTOC = toc && toc.length > 0;
|
||||
const showDesktopTOC = canRenderTOC &&
|
||||
(windowSize === 'desktop' || windowSize === 'ssr');
|
||||
|
||||
return (
|
||||
<Layout title={title} description={description}>
|
||||
<main className="container container--fluid margin-vert--lg">
|
||||
<div className="row">
|
||||
<div className={`col ${styles.col}`}>
|
||||
<div className={clsx(
|
||||
'col',
|
||||
styles.col,
|
||||
canRenderTOC && styles.colWithTOC
|
||||
)}>
|
||||
<div className={styles.container}>
|
||||
<article>
|
||||
{children}
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{showDesktopTOC && (
|
||||
<div className="col col--3">
|
||||
<TOC
|
||||
toc={toc}
|
||||
minHeadingLevel={2}
|
||||
maxHeadingLevel={2}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
max-width: 80%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* Narrower max-width when TOC is present to make room for the TOC column */
|
||||
.colWithTOC {
|
||||
max-width: 75%;
|
||||
}
|
||||
}
|
||||
|
||||
.container {
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
import { BarChart as RechartsBarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts';
|
||||
|
||||
export default function BarChart({ data, config }) {
|
||||
const showXAxis = config.showXAxis !== false;
|
||||
const showYAxis = config.showYAxis !== false;
|
||||
const showTooltip = config.showTooltip !== false;
|
||||
|
||||
return (
|
||||
<RechartsBarChart
|
||||
style={{ width: '100%', height: '25rem' }}
|
||||
data={data}
|
||||
margin={{
|
||||
top: 20,
|
||||
right: 0,
|
||||
left: 0,
|
||||
bottom: 20,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
{showXAxis && (
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
interval={0}
|
||||
angle={-45}
|
||||
textAnchor="end"
|
||||
height={120}
|
||||
tick={{ dy: 40 }}
|
||||
{...(config.xAxisLabel && { label: { value: config.xAxisLabel, position: 'insideBottom', offset: -5 } })}
|
||||
/>
|
||||
)}
|
||||
{showYAxis && (
|
||||
<YAxis label={{ value: config.yAxisLabel, angle: -90, position: 'insideLeft' }} />
|
||||
)}
|
||||
{showTooltip && <Tooltip />}
|
||||
<Bar dataKey="value" fill="#888888" />
|
||||
</RechartsBarChart>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import React from 'react';
|
||||
import { BarChart as RechartsBarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts';
|
||||
|
||||
export default function HorizontalBarChart({ data, config }) {
|
||||
const showXAxis = config.showXAxis !== false;
|
||||
const showYAxis = config.showYAxis !== false;
|
||||
const showTooltip = config.showTooltip !== false;
|
||||
|
||||
// Calculate height based on number of bars (48px per bar + margins)
|
||||
const barHeight = 48;
|
||||
const chartHeight = (data.length * barHeight) + 60;
|
||||
|
||||
return (
|
||||
<RechartsBarChart
|
||||
layout="vertical"
|
||||
style={{ width: '100%', height: chartHeight }}
|
||||
data={data}
|
||||
margin={{
|
||||
top: 0,
|
||||
right: 0,
|
||||
left: 0,
|
||||
bottom: 30, // Space for x-axis label
|
||||
}}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
{showYAxis && (
|
||||
<YAxis
|
||||
type="category"
|
||||
dataKey="name"
|
||||
width={250}
|
||||
tick={{ fontSize: 12 }}
|
||||
{...(config.yAxisLabel && { label: { value: config.yAxisLabel, angle: -90, position: 'insideLeft' } })}
|
||||
/>
|
||||
)}
|
||||
{showXAxis && (
|
||||
<XAxis
|
||||
type="number"
|
||||
{...(config.xAxisLabel && { label: { value: config.xAxisLabel, position: 'insideBottom', offset: -5 } })}
|
||||
/>
|
||||
)}
|
||||
{showTooltip && <Tooltip />}
|
||||
<Bar dataKey="value" fill="#888888" />
|
||||
</RechartsBarChart>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend } from 'recharts';
|
||||
|
||||
export default function StackedBarChart({ data, config, categories }) {
|
||||
const colors = ['#0077BB', '#EE7733', '#009988', '#CCBB44', '#CC3311', '#AA3377'];
|
||||
|
||||
const showXAxis = config.showXAxis !== false;
|
||||
const showYAxis = config.showYAxis !== false;
|
||||
const showTooltip = config.showTooltip !== false;
|
||||
const showLegend = config.showLegend !== false;
|
||||
|
||||
return (
|
||||
<BarChart
|
||||
style={{ width: '100%', height: '25rem' }}
|
||||
data={data}
|
||||
margin={{
|
||||
top: 20,
|
||||
right: 0,
|
||||
left: 0,
|
||||
bottom: 20,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
{showXAxis && (
|
||||
<XAxis
|
||||
dataKey="name"
|
||||
interval={0}
|
||||
angle={-45}
|
||||
textAnchor="end"
|
||||
height={120}
|
||||
tick={{ dy: 40 }}
|
||||
{...(config.xAxisLabel && { label: { value: config.xAxisLabel, position: 'insideBottom', offset: -5 } })}
|
||||
/>
|
||||
)}
|
||||
{showYAxis && (
|
||||
<YAxis label={{ value: config.yAxisLabel, angle: -90, position: 'insideLeft' }} />
|
||||
)}
|
||||
{showTooltip && <Tooltip />}
|
||||
{showLegend && <Legend />}
|
||||
{categories.map((category, index) => (
|
||||
<Bar
|
||||
key={category}
|
||||
dataKey={category}
|
||||
stackId="a"
|
||||
fill={colors[index % colors.length]}
|
||||
/>
|
||||
))}
|
||||
</BarChart>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
export default function TextList({ intro, bullets, config }) {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
{intro && (
|
||||
<p className={styles.intro}>{intro}</p>
|
||||
)}
|
||||
{bullets && bullets.length > 0 && (
|
||||
<ul className={styles.bullets}>
|
||||
{bullets.map((bullet, index) => (
|
||||
<li key={index} className={styles.bulletItem}>
|
||||
<strong>{bullet.title}</strong> ({bullet.count} {bullet.count === 1 ? 'response' : 'responses'}): {bullet.sentence}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
.container {
|
||||
max-width: 700px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.intro {
|
||||
margin-bottom: 1rem;
|
||||
color: var(--ifm-color-emphasis-700);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.bullets {
|
||||
list-style: disc;
|
||||
padding-left: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.bulletItem {
|
||||
margin-bottom: 0.5rem;
|
||||
line-height: 1.5;
|
||||
font-weight: 500;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import BarChart from './BarChart';
|
||||
import StackedBarChart from './StackedBarChart';
|
||||
import TextList from './TextList';
|
||||
import HorizontalBarChart from './HorizontalBarChart';
|
||||
|
||||
export const chartRegistry = {
|
||||
'bar': BarChart,
|
||||
'stacked-bar': StackedBarChart,
|
||||
'text-list': TextList,
|
||||
'horizontal-bar': HorizontalBarChart,
|
||||
};
|
||||
|
||||
export function getChartComponent(chartType) {
|
||||
return chartRegistry[chartType] || null;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "< 3 months",
|
||||
"value": 24
|
||||
},
|
||||
{
|
||||
"label": "3-6 months",
|
||||
"value": 26
|
||||
},
|
||||
{
|
||||
"label": "6-12 months",
|
||||
"value": 25
|
||||
},
|
||||
{
|
||||
"label": "Over 12 months",
|
||||
"value": 25
|
||||
}
|
||||
]
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "< 10",
|
||||
"value": 43
|
||||
},
|
||||
{
|
||||
"label": "10-50",
|
||||
"value": 32
|
||||
},
|
||||
{
|
||||
"label": "50-200",
|
||||
"value": 14
|
||||
},
|
||||
{
|
||||
"label": "200+",
|
||||
"value": 12
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"slug": "2021",
|
||||
"title": "2021 OPA Community Survey",
|
||||
"year": 2021,
|
||||
"blog": "https://blog.openpolicyagent.org/open-policy-agent-2021-survey-summary-e749bbd7b824",
|
||||
"intro": "This page presents selected results from the 2021 OPA Community Survey for comparison across years. For the full survey results and detailed analysis, please see the blog post.",
|
||||
"sections": [
|
||||
{
|
||||
"tag": "general",
|
||||
"title": "General",
|
||||
"description": "This section contains questions seen by all respondents and is intended to give a high level overview of how OPA is used."
|
||||
},
|
||||
{
|
||||
"tag": "demographic",
|
||||
"title": "Demographics",
|
||||
"description": "These questions are shown to all respondents and are intended to be used for comparisons with other questions and other survey years."
|
||||
}
|
||||
]
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"data": [
|
||||
{ "label": "Evaluating/Experimentation", "value": 33 },
|
||||
{ "label": "Pre-production & QA", "value": 32 },
|
||||
{ "label": "Production", "value": 35 }
|
||||
],
|
||||
"footnotes": []
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Kubernetes Admission Control",
|
||||
"value": 54
|
||||
},
|
||||
{
|
||||
"label": "Application authorization",
|
||||
"value": 39
|
||||
},
|
||||
{
|
||||
"label": "Microservice Authorization",
|
||||
"value": 39
|
||||
},
|
||||
{
|
||||
"label": "Terraform validation",
|
||||
"value": 25
|
||||
},
|
||||
{
|
||||
"label": "Other",
|
||||
"value": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Not using OPA",
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"label": "< 3 months",
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"label": "3-6 months",
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"label": "6-12 months",
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"label": "Over 12 months",
|
||||
"value": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"slug": "2022",
|
||||
"title": "2022 OPA Community Survey",
|
||||
"year": 2022,
|
||||
"blog": "https://blog.openpolicyagent.org/open-policy-agent-2022-user-survey-summary-370cf0243bb7",
|
||||
"intro": "This page presents selected results from the 2022 OPA Community Survey for comparison across years. For the full survey results and detailed analysis, please see the blog post.",
|
||||
"sections": [
|
||||
{
|
||||
"tag": "general",
|
||||
"title": "General",
|
||||
"description": "This section contains questions seen by all respondents and is intended to give a high level overview of how OPA is used."
|
||||
},
|
||||
{
|
||||
"tag": "demographic",
|
||||
"title": "Demographics",
|
||||
"description": "These questions are shown to all respondents and are intended to be used for comparisons with other questions and other survey years."
|
||||
}
|
||||
]
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"data": [
|
||||
{ "label": "Evaluating/Experimentation", "value": 30 },
|
||||
{ "label": "Pre-production & QA", "value": 27 },
|
||||
{ "label": "Production", "value": 43 }
|
||||
],
|
||||
"footnotes": [
|
||||
"The use case question split the evaluating and experimenting options, these are grouped here to make comparisons between years easier. Evaluation was 12% and experimentation was 18%, combined to give 30% as we see here."
|
||||
]
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "32 responses were summarized as follows, showing interest across a broad range integration options.",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Data & State Management",
|
||||
"count": 7,
|
||||
"sentence": "Users want better solutions for handling external data, from \"on demand data ingestion\" for high-volume volatile data to \"a good shared cache for OPAs in same kubernetes namespace\" and the ability to \"load a baseline dataset from a bundle file and amend that via rest api.\""
|
||||
},
|
||||
{
|
||||
"title": "Standards & Protocol Support",
|
||||
"count": 6,
|
||||
"sentence": "Requests for broader protocol and API support, including \"OpenID AuthZEN API support,\" \"OPA running as gRPC,\" and more \"first-party\" integrations like \"AuthZen and Rebac out-of-the-box.\""
|
||||
},
|
||||
{
|
||||
"title": "Enterprise & Operational Features",
|
||||
"count": 6,
|
||||
"sentence": "Need for production-ready capabilities such as \"full stack OTEL integration with Grafana,\" \"disk buffering for decision logs,\" \"s3 export of logs,\" and \"a builtin control plane.\""
|
||||
},
|
||||
{
|
||||
"title": "Documentation & Tooling",
|
||||
"count": 4,
|
||||
"sentence": "Gaps in guidance and developer experience, from \"better documentation on OPA side car components\" to \"proper CLI installation for Linux machines\" and package management where \"a OPA lib can depend on remote OPA policy.\""
|
||||
}
|
||||
]
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "39 responses were summarized and grouped, we still see that generative models still struggle with the Rego syntax.",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Failures/Limitations",
|
||||
"count": 15,
|
||||
"sentence": "LLMs struggle with Rego's unique syntax, often \"hallucinating\" features, generating \"python-like code,\" or producing outdated v0 syntax like \"the old name { ... } syntax without the if\" despite recent language updates."
|
||||
},
|
||||
{
|
||||
"title": "Mixed/Moderate Success",
|
||||
"count": 7,
|
||||
"sentence": "AI can be helpful for specific tasks like \"debugging operations,\" \"drafting the rego rules,\" or \"convert some pretty nasty v0 rego to v1,\" though manual edits are typically still required."
|
||||
},
|
||||
{
|
||||
"title": "Haven't Tried/N/A",
|
||||
"count": 12,
|
||||
"sentence": "Many respondents haven't explored AI tooling yet, with some noting they \"prefer understanding what I'm doing first\" or simply haven't needed to update policies since GenAI became widely available."
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Regal",
|
||||
"value": 52
|
||||
},
|
||||
{
|
||||
"label": "OPA Gatekeeper",
|
||||
"value": 23
|
||||
},
|
||||
{
|
||||
"label": "Conftest",
|
||||
"value": 18
|
||||
},
|
||||
{
|
||||
"label": "OPA Envoy Plugin",
|
||||
"value": 14
|
||||
}
|
||||
],
|
||||
"footnotes": [
|
||||
"Survey respondents are only shown project-specific questions if they indicate they are using that project"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Startup (1-50 employees)",
|
||||
"value": 15
|
||||
},
|
||||
{
|
||||
"label": "Small (51-200 employees)",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "Medium (201-1,000 employees)",
|
||||
"value": 13
|
||||
},
|
||||
{
|
||||
"label": "Large (1,001-10,000 employees)",
|
||||
"value": 18
|
||||
},
|
||||
{
|
||||
"label": "Enterprise (10,000+ employees)",
|
||||
"value": 26
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "USA",
|
||||
"value": 31
|
||||
},
|
||||
{
|
||||
"label": "Germany",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "Sweden",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Canada",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Norway",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Netherlands",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "India",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "Spain",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "Italy",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "Denmark",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "France",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Japan",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Austria",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "China",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "New Zealand",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "UK",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Australia",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Ireland",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Malaysia",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Brazil",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Latvia",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Israel",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "5 responses",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Insufficient Documentation",
|
||||
"count": 2,
|
||||
"sentence": "Users find gaps in the current docs, noting they do \"not provide details on the interfaces\" and lack clarity on \"the mapping between a request and a policy\" or \"how to evaluate multiple policies against a single request.\""
|
||||
}
|
||||
]
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "5 responses",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Time-Based & Contextual Access",
|
||||
"count": 1,
|
||||
"sentence": "Users want dynamic authorization, such as granting \"time based access to support engineers to 'unblock' users in emergency situations where the risk of being down outweighs the security violations.\""
|
||||
},
|
||||
{
|
||||
"title": "Resource Segmentation",
|
||||
"count": 1,
|
||||
"sentence": "Teams need finer controls \"to restrict certain use cases to segregated nodes.\""
|
||||
}
|
||||
]
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "19 responses",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Strong Appreciation",
|
||||
"count": 7,
|
||||
"sentence": "Users are enthusiastic about Regal, calling it \"best tool ever\" that \"augments Rego learning,\" with many finding it \"the best source of documentation for idiomatic Rego\" and valuing how it \"defines some common guidelines for how Rego code should look.\""
|
||||
},
|
||||
{
|
||||
"title": "Feature Requests",
|
||||
"count": 4,
|
||||
"sentence": "Users want expanded capabilities, particularly \"find references\" and \"LSP rename\" for improved workflow, more \"auto fixable rules,\" and wish \"the examples on the OPA website were using rego that has zero violations from regal.\""
|
||||
},
|
||||
{
|
||||
"title": "Usability Challenges",
|
||||
"count": 4,
|
||||
"sentence": "Some encounter friction, including Regal not reloading properly in VS Code requiring full restarts, difficulty with the debugger in Zed, rules that are \"hard to understand from documentation,\" and confusion \"when migrating code pre v1.\""
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Sometimes - mixed results",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "Yes, catches bugs before deployment",
|
||||
"value": 21
|
||||
},
|
||||
{
|
||||
"label": "Yes, but only basic issues",
|
||||
"value": 16
|
||||
},
|
||||
{
|
||||
"label": "No, haven't found it helpful",
|
||||
"value": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Sometimes, I find some rules harder to understand",
|
||||
"value": 17
|
||||
},
|
||||
{
|
||||
"label": "Yes, I find the rule documentation and examples easy to learn from",
|
||||
"value": 23
|
||||
},
|
||||
{
|
||||
"label": "No, haven't found it helpful for bug fixing",
|
||||
"value": 3
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"N/A"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Strongly disagree",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"label": "Disagree",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"label": "Somewhat disagree",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Neither agree nor disagree",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"label": "Somewhat agree",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Agree",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "Strongly agree",
|
||||
"value": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "59 responses were grouped and summarized as follows",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Work/Colleagues",
|
||||
"count": 18,
|
||||
"sentence": "Discovered through workplace connections, whether introduced by \"architects\" or \"consultants,\" learning from coworkers, or joining teams where OPA was already in use."
|
||||
},
|
||||
{
|
||||
"title": "Kubernetes/Cloud Native Ecosystem",
|
||||
"count": 15,
|
||||
"sentence": "Found via the cloud native community through KubeCon events, CNCF resources, Gatekeeper, or while researching \"PodSecurityPolicy being deprecated by Kubernetes.\""
|
||||
},
|
||||
{
|
||||
"title": "Research/Web Search",
|
||||
"count": 12,
|
||||
"sentence": "Discovered independently while searching for authorization and policy solutions, from \"browsing for available policy frameworks\" to finding \"a way to replace our home-developed authorization microservice.\""
|
||||
},
|
||||
{
|
||||
"title": "Product Integrations",
|
||||
"count": 6,
|
||||
"sentence": "Encountered through existing tools and documentation, including \"Trino integration,\" \"Envoy ext_authz examples,\" and \"HashiCorp's website.\""
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "As a standalone service",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"label": "As a sidecar alongside Envoy when Envoy is deployed as a sidecar",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "As a sidecar alongside Envoy when Envoy is deployed as a standalone service",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Via files built into the container filesystem",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "Via files mounted into the container filesystem at runtime (configmap, etc)",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Via a bundle server",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "Via bundles mounted or built into the container filesystem",
|
||||
"value": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "We do not use OPA for this use case.",
|
||||
"value": 65
|
||||
},
|
||||
{
|
||||
"label": "Prompt filtering",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Prompt governance",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "Response filtering",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Response governance",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Prompt injection/augmentation",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "Response transformation",
|
||||
"value": 1
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"Data filtering for rag"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Use it in CI",
|
||||
"value": 39
|
||||
},
|
||||
{
|
||||
"label": "Use CLI",
|
||||
"value": 28
|
||||
},
|
||||
{
|
||||
"label": "Use language server in my editor",
|
||||
"value": 32
|
||||
},
|
||||
{
|
||||
"label": "Step by step debugging via DAP",
|
||||
"value": 7
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"Since our policies are dynamic by nature, I use the LS when debugging buggy generated policies"
|
||||
]
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Object Storage (S3, GCS, etc.)",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "OCI / Docker images (Dockerhub, GHCR, GAR, etc.)",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"label": "Git",
|
||||
"value": 12
|
||||
}
|
||||
]
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Very difficult",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"label": "Difficult",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Somewhat difficult",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Neither easy nor difficult",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "Somewhat easy",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "Easy",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "Very easy",
|
||||
"value": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Very unlikely",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"label": "Unlikely",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"label": "Somewhat unlikely",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Neither likely nor unlikely",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Somewhat likely",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "Likely",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "Very likely",
|
||||
"value": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "< 3 months",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "6-12months",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"label": "more than 12 months",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "more than 2 years",
|
||||
"value": 6
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "< 3 months",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "3-6 months",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "6-12 months",
|
||||
"value": 16
|
||||
},
|
||||
{
|
||||
"label": "Over 12 months",
|
||||
"value": 15
|
||||
},
|
||||
{
|
||||
"label": "more than 2 years",
|
||||
"value": 39
|
||||
}
|
||||
],
|
||||
"footnotes": [
|
||||
"Response labels have been normalized across survey years to enable comparison (e.g., 'Just started' and '< 3 months' are treated as equivalent)"
|
||||
]
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "< 10",
|
||||
"value": 56
|
||||
},
|
||||
{
|
||||
"label": "10-50",
|
||||
"value": 12
|
||||
},
|
||||
{
|
||||
"label": "50-200",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "200+",
|
||||
"value": 12
|
||||
}
|
||||
]
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "1",
|
||||
"value": 24
|
||||
},
|
||||
{
|
||||
"label": "2-5",
|
||||
"value": 31
|
||||
},
|
||||
{
|
||||
"label": "6-10",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "11-50",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "more than 50",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "I don't know",
|
||||
"value": 12
|
||||
}
|
||||
]
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Daily/Weekly - Regular policy development",
|
||||
"value": 21
|
||||
},
|
||||
{
|
||||
"label": "Monthly - Occasional policy updates",
|
||||
"value": 17
|
||||
},
|
||||
{
|
||||
"label": "Rarely - Only when necessary",
|
||||
"value": 12
|
||||
},
|
||||
{
|
||||
"label": "Not yet - Planning to start",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Very dissatisfied",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"label": "Somewhat dissatisfied",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"label": "Neither satisfied nor dissatisfied",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Somewhat satisfied",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "Satisfied",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "Very satisfied",
|
||||
"value": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Just evaluating / experimenting",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Running in full production across multiple workloads or clusters",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "Previously used but no longer using",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "Running in limited production workloads",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "Running in a development or test environment",
|
||||
"value": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "No experience - Never used Kubernetes",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Beginner - Basic knowledge, learning fundamentals",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "Intermediate - Regular use, comfortable with common tasks",
|
||||
"value": 6
|
||||
},
|
||||
{
|
||||
"label": "Advanced - Deep knowledge, complex deployments and troubleshooting",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "Expert - Architect solutions, contribute to community, mentor others",
|
||||
"value": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Beginner - Basic understanding, experimenting with simple policies",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Intermediate - Write and maintain policies, integrate into CI/CD pipelines",
|
||||
"value": 10
|
||||
},
|
||||
{
|
||||
"label": "Expert - Architect enterprise policy solutions, contribute to tools, lead implementations",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "Advanced - Design complex policy frameworks, implement governance at scale",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "No experience - Never used policy-as-code tools",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "OPA website",
|
||||
"value": 81
|
||||
},
|
||||
{
|
||||
"label": "Rego Playground",
|
||||
"value": 62
|
||||
},
|
||||
{
|
||||
"label": "VS Code and other editor extensions",
|
||||
"value": 23
|
||||
},
|
||||
{
|
||||
"label": "Regal",
|
||||
"value": 32
|
||||
},
|
||||
{
|
||||
"label": "AI Chatbot or other LLM tool",
|
||||
"value": 22
|
||||
},
|
||||
{
|
||||
"label": "OPA videos on Youtube",
|
||||
"value": 22
|
||||
},
|
||||
{
|
||||
"label": "OPA at KubeCon or other conference",
|
||||
"value": 12
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"Used Styra academy. The course with OPA example was really useful",
|
||||
"Writing a book",
|
||||
"Slack (Help) Channel",
|
||||
"I think Styra had some courses at some point, they were good. They are probably migrated to the OPA website at this point.",
|
||||
"Cloud Native Foundation",
|
||||
"Styra Trainings",
|
||||
"Work",
|
||||
"Styra Academy",
|
||||
"Styra Academy",
|
||||
"The Internet",
|
||||
"opa slack workspace!",
|
||||
"consultants",
|
||||
"Consultants",
|
||||
"Struggling through it in ~2019",
|
||||
"Styra Academy",
|
||||
"Fugue/Regula"
|
||||
]
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Bundles",
|
||||
"value": 58
|
||||
},
|
||||
{
|
||||
"label": "Decision logs",
|
||||
"value": 51
|
||||
},
|
||||
{
|
||||
"label": "REST API*",
|
||||
"value": 31
|
||||
},
|
||||
{
|
||||
"label": "Status",
|
||||
"value": 28
|
||||
},
|
||||
{
|
||||
"label": "Delta bundles",
|
||||
"value": 9
|
||||
}
|
||||
],
|
||||
"footnotes": [
|
||||
"* REST API for policy management or non policy evaluation use cases"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "At work",
|
||||
"value": 84
|
||||
},
|
||||
{
|
||||
"label": "For personal use",
|
||||
"value": 16
|
||||
},
|
||||
{
|
||||
"label": "At my second job or side project",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "While doing charity work or volunteering",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Short term contracts",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "I don't use OPA at all these days",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "I don't use OPA yet",
|
||||
"value": 1
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"study FGA with OPA"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Go",
|
||||
"value": 25
|
||||
},
|
||||
{
|
||||
"label": "Java",
|
||||
"value": 6
|
||||
},
|
||||
{
|
||||
"label": "Javascript",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "CEL",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "Typescript",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "SQL",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Prolog",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "None of the above",
|
||||
"value": 28
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"\"When I see your face There's not a thing that I would change 'Cause you're amazing Just the way you are\" -Bruno Mars",
|
||||
"We experience that developers have a difficult time learning Rego. Also teams arent motivated to learn it since after you have written your authorization policy for our API, it rarely need to be updated, not daily at least as your programs often do. So they dont want to use time learning a language they use a couple of times a year.",
|
||||
"YAML/JSON",
|
||||
"Python",
|
||||
"python",
|
||||
"honestly it's pretty good as it is",
|
||||
"OCaml",
|
||||
"Yaml",
|
||||
"Python",
|
||||
"kotlin, simplified; may be groovy with types inference"
|
||||
]
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Team dynamics, buy-in",
|
||||
"value": 22
|
||||
},
|
||||
{
|
||||
"label": "Lack of familiarity over in-house approaches",
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"label": "Deployment and management overhead",
|
||||
"value": 11
|
||||
},
|
||||
{
|
||||
"label": "Missing integrations",
|
||||
"value": 9
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"Lack of clear documentation",
|
||||
"Rego complexity",
|
||||
"Product immaturity",
|
||||
"lack of a data plane",
|
||||
"To authorize an API call we often rely on data that is too large to be loaded into OPA, e.g. data in a database. Maybe have missed it, or just havent looked hard enough, but we find it difficult to fetch data from a database in Rego.",
|
||||
"management don't understand it",
|
||||
"OPA syntax too complicated. compare to other language i had to think more times",
|
||||
"No support for custom authorization webhook",
|
||||
"Staffing",
|
||||
"custom engine based on Groovy scripting"
|
||||
]
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "34 responses tell a pretty strong story about not having time to contribute to OPA, among other reasons.",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Time Constraints",
|
||||
"count": 13,
|
||||
"sentence": "The most common barrier is simply bandwidth, with many citing \"only so much time in the day,\" competing \"priorities at work,\" and \"other tasks with higher priorities.\""
|
||||
},
|
||||
{
|
||||
"title": "Skills & Knowledge Gaps",
|
||||
"count": 7,
|
||||
"sentence": "Many feel underprepared, whether \"not familiar with go,\" still on the \"learning curve,\" or feeling \"not that advanced user yet\" to know what they could contribute."
|
||||
},
|
||||
{
|
||||
"title": "Unclear Entry Points",
|
||||
"count": 3,
|
||||
"sentence": "Some want to contribute but lack direction, \"not sure what other contributions are welcome or needed\" or actively \"looking for my first issue to contribute to now\" and needing \"good first issues.\""
|
||||
},
|
||||
{
|
||||
"title": "Company Policies & Restrictions",
|
||||
"count": 2,
|
||||
"sentence": "Organizational barriers prevent some from participating, including \"company policy on open-source contribution\" and workplaces \"not known for open-source contributions.\""
|
||||
}
|
||||
]
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Go",
|
||||
"value": 52
|
||||
},
|
||||
{
|
||||
"label": "Python",
|
||||
"value": 47
|
||||
},
|
||||
{
|
||||
"label": "Java",
|
||||
"value": 40
|
||||
},
|
||||
{
|
||||
"label": "JavaScript/TypeScript",
|
||||
"value": 34
|
||||
},
|
||||
{
|
||||
"label": "Rust",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "Shell/Bash",
|
||||
"value": 27
|
||||
},
|
||||
{
|
||||
"label": "C/C++",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "C#/.NET",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "Ruby",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "Kotlin",
|
||||
"value": 4
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"PHP",
|
||||
"PHP",
|
||||
"Zig",
|
||||
"PHP",
|
||||
"SQL",
|
||||
"PowerShell"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"slug": "2025",
|
||||
"title": "2025 OPA Community Survey",
|
||||
"year": 2025,
|
||||
"intro": "This page presents the results from the 2025 OPA Community Survey. The survey was run at the end of 2025 online and during the KubeCon event in Atlanta.",
|
||||
"sections": [
|
||||
{
|
||||
"tag": "general",
|
||||
"title": "General",
|
||||
"description": "This section contains questions seen by all respondents and is intended to give a high level overview of how OPA is used."
|
||||
},
|
||||
{
|
||||
"tag": "gatekeeper",
|
||||
"title": "Gatekeeper",
|
||||
"description": "This section contains questions only shown to users who answered yes to using [Gatekeeper](https://open-policy-agent.github.io/gatekeeper/website/) and is intended to give a more detailed overview of OPA Gatekeeper users and their use cases."
|
||||
},
|
||||
{
|
||||
"tag": "opa-envoy-plugin",
|
||||
"title": "OPA Envoy Plugin",
|
||||
"description": "These questions were only shown to users who said they were using [opa-envoy-plugin](https://www.openpolicyagent.org/docs/envoy). They are intended to shed light on where OPA Envoy Plugin is used, and how it can be made easier to use."
|
||||
},
|
||||
{
|
||||
"tag": "conftest",
|
||||
"title": "Conftest",
|
||||
"description": "The following questions were only answered by users who said they were using the tool. They show how users typically invoke [Conftest](https://www.conftest.dev) and where they source policies from."
|
||||
},
|
||||
{
|
||||
"tag": "regal",
|
||||
"title": "Regal",
|
||||
"description": "These questions are only answered by users of [Regal](https://openpolicyagent.org/projects/regal), the main developer tooling stack for Rego programmers. The questions shed light on how different features are used and where users find value in the project."
|
||||
},
|
||||
{
|
||||
"tag": "demographic",
|
||||
"title": "Demographics",
|
||||
"description": "These questions are shown to all respondents and are intended to be used for comparisons with other questions and other survey years."
|
||||
}
|
||||
]
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "<10ms",
|
||||
"value": 30
|
||||
},
|
||||
{
|
||||
"label": "<20ms",
|
||||
"value": 17
|
||||
},
|
||||
{
|
||||
"label": "<100ms",
|
||||
"value": 16
|
||||
},
|
||||
{
|
||||
"label": "<500ms",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "500ms+",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "I don't know",
|
||||
"value": 17
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "VS Code",
|
||||
"value": 48
|
||||
},
|
||||
{
|
||||
"label": "Emacs",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Jetbrains IDE",
|
||||
"value": 18
|
||||
},
|
||||
{
|
||||
"label": "Vim/Neovim",
|
||||
"value": 8
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"Cursor",
|
||||
"Helix",
|
||||
"Zed",
|
||||
"Zed",
|
||||
"(VS Code or Zed) with Vim keybindings",
|
||||
"Eclipse",
|
||||
"Cursor",
|
||||
"Cursor",
|
||||
"Zed"
|
||||
]
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "28 responses were summarized showing a broad range of experiences.",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Successful Implementations",
|
||||
"count": 8,
|
||||
"sentence": "Teams have found success using OPA for diverse use cases, from \"fine-grained Kubernetes security policy\" with Gatekeeper to \"auth across multiple Trino instances\" and \"decoupling permissions from our legacy monolith system,\" with one team seeing dramatic improvements where \"10000 policies causing a JWT token request timeout\" dropped to \"around 200ms\" with OPA."
|
||||
},
|
||||
{
|
||||
"title": "Learning Curve Challenges",
|
||||
"count": 5,
|
||||
"sentence": "Adoption friction centers on Rego's declarative nature, where \"teams have a hard time learning Rego\" and \"error handling is weird\" — particularly the concept that \"if some value is undefined the top rule is also undefined.\""
|
||||
},
|
||||
{
|
||||
"title": "Architectural & Integration Hurdles",
|
||||
"count": 5,
|
||||
"sentence": "Organizations struggle with complex integration patterns, from \"how to handle 'global' or enterprise policies at the gateway level and 'local' policies at the application level\" to converting \"arbitrary rules to SQL for filter requests\" and wanting \"better GraphQL support.\""
|
||||
},
|
||||
{
|
||||
"title": "Organizational & Trust Concerns",
|
||||
"count": 3,
|
||||
"sentence": "Business adoption faces resistance, with \"strong pushback on OPA and externalized authz in general\" and a need for \"supporting tooling\" like control planes and management apps to ease introduction."
|
||||
}
|
||||
]
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "3 responses were summarized",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Use Case Guidance",
|
||||
"count": 1,
|
||||
"sentence": "Users want documentation for complex scenarios, particularly \"global and local policies\" in \"a multi-tenant (namespaced) cluster where there are enterprise level policies at the gateway and local policies at tenants.\""
|
||||
}
|
||||
]
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Istio Ambient",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"label": "Envoy Gateway",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "Contour",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "Kgateway",
|
||||
"value": 1
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"-"
|
||||
]
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "7 responses were summarized",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Documentation & Guidance Gaps",
|
||||
"count": 2,
|
||||
"sentence": "Users struggle with \"lack of documentation\" and want clearer guidance on patterns like \"leveraging SPIRE/SPIFFE identities for microservice authentication\" — noting \"there might be room for clearly documenting that as a good option.\""
|
||||
},
|
||||
{
|
||||
"title": "Development & Data Challenges",
|
||||
"count": 2,
|
||||
"sentence": "Practical hurdles include \"local development without kubernetes\" requiring nginx workarounds, and \"getting external data into it,\" leading teams to build custom bundle servers."
|
||||
},
|
||||
{
|
||||
"title": "Release & Policy Management",
|
||||
"count": 2,
|
||||
"sentence": "Operational concerns include being \"always behind the main OPA releases by few days\" and difficulties \"evaluating multiple policies.\""
|
||||
}
|
||||
]
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "4 responses were summarized",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Stability & Upgrades",
|
||||
"count": 2,
|
||||
"sentence": "Users prioritize reliable version management, whether valuing \"smooth upgrades\" or needing to \"get up to speed with the latest versions\" before evaluating new features."
|
||||
}
|
||||
]
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Manage Mutating Admission Policies similar to Validating Admission Policies",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "Support for validating authorization webhooks",
|
||||
"value": 5
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"generate feature",
|
||||
"Shared libs"
|
||||
]
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Ext_proc support",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Support an opinionated set of builtin helpers for common SPIFFE ID authorization tasks?",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "Ext_authz HTTP API support",
|
||||
"value": 3
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"Source and Destination Spiffe in input when using ambient mode."
|
||||
]
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "9 responses were summarized",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Complexity & Usability",
|
||||
"count": 3,
|
||||
"sentence": "Users find Gatekeeper \"overcomplicated for simple use cases,\" with the \"constraints + constraint templates\" structure feeling like \"a bit too much cruft\" for simple tasks like enforcing a label, and \"not always easy to debug policy failures.\""
|
||||
},
|
||||
{
|
||||
"title": "Architecture Limitations",
|
||||
"count": 3,
|
||||
"sentence": "Technical gaps frustrate users, particularly the \"lack of shared lib support and hierarchical policy support\" and \"no simple way to embed rego policy at scale into the constraint template\" while maintaining separate files for unit tests."
|
||||
}
|
||||
]
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"data": [],
|
||||
"intro": "8 responses were summarized",
|
||||
"bullets": [
|
||||
{
|
||||
"title": "Reliability & Standardization",
|
||||
"count": 3,
|
||||
"sentence": "Users appreciate that Gatekeeper simply works — \"it works,\" \"it just works,\" and it's become \"the de-facto standard versus alternatives like Kyverno.\""
|
||||
},
|
||||
{
|
||||
"title": "Functionality & Integration",
|
||||
"count": 3,
|
||||
"sentence": "Teams value the capabilities it provides, from \"advanced admission control\" and \"policy guardrails/enforcement\" to easy \"integration into our current build process.\""
|
||||
}
|
||||
]
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Evaluating/Experimentation",
|
||||
"value": 18
|
||||
},
|
||||
{
|
||||
"label": "Pre-production & QA",
|
||||
"value": 14
|
||||
},
|
||||
{
|
||||
"label": "Production",
|
||||
"value": 56
|
||||
}
|
||||
]
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "gRPC",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "Envoy Proxy",
|
||||
"value": 6
|
||||
},
|
||||
{
|
||||
"label": "Istio",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "Envoy Gateway",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"label": "SPIFFE/SPIRE",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "Contour",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "cert-manager",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Kgateway",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Gloo",
|
||||
"value": 2
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"Skipper"
|
||||
]
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "<10ms",
|
||||
"value": 20
|
||||
},
|
||||
{
|
||||
"label": "<20ms",
|
||||
"value": 14
|
||||
},
|
||||
{
|
||||
"label": "<100ms",
|
||||
"value": 11
|
||||
},
|
||||
{
|
||||
"label": "<500ms",
|
||||
"value": 6
|
||||
},
|
||||
{
|
||||
"label": "depends on policy",
|
||||
"value": 22
|
||||
},
|
||||
{
|
||||
"label": "It varies a lot",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "I don't know",
|
||||
"value": 31
|
||||
}
|
||||
]
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "test",
|
||||
"value": 15
|
||||
},
|
||||
{
|
||||
"label": "fmt",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "parse",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "verify",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "pull",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "push",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "doc",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "reformat",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "kubectl",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "plugin",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Sync (syncing Kubernetes objects into OPA for policy decisions)",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "ConstraintTemplates & Constraints",
|
||||
"value": 18
|
||||
},
|
||||
{
|
||||
"label": "Mutation",
|
||||
"value": 10
|
||||
},
|
||||
{
|
||||
"label": "Audit functionality",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "External data (e.g., validating against external systems/APIs)",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "Exemptions / namespace exclusions",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "Metrics / monitoring integration (Prometheus, etc.)",
|
||||
"value": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Vanilla K8s",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"label": "OpenShift",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "EKS",
|
||||
"value": 6
|
||||
},
|
||||
{
|
||||
"label": "AKS",
|
||||
"value": 3
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"EKS and AKS",
|
||||
"KCC",
|
||||
"Rancher"
|
||||
]
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Gatekeeper policy library",
|
||||
"value": 23
|
||||
},
|
||||
{
|
||||
"label": "Library, Community-owned policy library for OPA",
|
||||
"value": 25
|
||||
},
|
||||
{
|
||||
"label": "Red Hat Rego policies",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "Appshield - Open Database of Rego policies for common IaC file",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "Kubescape Rego library",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"label": "Conftest policy packs",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"label": "Confectionary Terraform rules for Conftest",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"label": "Raspernetes Kubernetes Security Policies",
|
||||
"value": 1
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"OPAL",
|
||||
"In-house created",
|
||||
"topaz",
|
||||
"We dont use libraries.",
|
||||
"none",
|
||||
"None"
|
||||
]
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Internal compliance & governance",
|
||||
"value": 28
|
||||
},
|
||||
{
|
||||
"label": "Application authorization",
|
||||
"value": 54
|
||||
},
|
||||
{
|
||||
"label": "CI/CD and supply-chain guardrails (SBOMs, Spinnaker, etc.)",
|
||||
"value": 13
|
||||
},
|
||||
{
|
||||
"label": "Kubernetes Admission Control",
|
||||
"value": 28
|
||||
},
|
||||
{
|
||||
"label": "Infrastructure-as-code Guardrails (Terraform, Cloudformation, other)",
|
||||
"value": 19
|
||||
},
|
||||
{
|
||||
"label": "Microservice Authorization",
|
||||
"value": 36
|
||||
},
|
||||
{
|
||||
"label": "External compliance (e.g., PCI)",
|
||||
"value": 10
|
||||
},
|
||||
{
|
||||
"label": "Customer IAM",
|
||||
"value": 14
|
||||
},
|
||||
{
|
||||
"label": "Staff IAM",
|
||||
"value": 19
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"Business logic decisions",
|
||||
"Data enrichment of SBOM data with EPSS, log detection as code",
|
||||
"API responses from AI powered tools",
|
||||
"Decentralised data authorisation for open standard data models",
|
||||
"fun!",
|
||||
"Using OPA as a business rule engine and love it",
|
||||
"Direct Data Access Authz (e.g. via Trino)",
|
||||
"Kubernetes Authorization Webhook",
|
||||
"AI MCP Enforcement, Customer-driven data transformations",
|
||||
"ACL",
|
||||
"Detection policy engine",
|
||||
"Loyalty rules evaluation (thousands of similar campaigns with common rules)",
|
||||
"Regal rules",
|
||||
"Cyber vulnerability data enrichment"
|
||||
]
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "OPA (Not Gatekeeper)",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "Kyverno",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "Conftest",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "Polaris",
|
||||
"value": 1
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"Cedar, CUE, JSPolicy, Cloud Custodian, Sentinel",
|
||||
"Cloud Custodian, CUE"
|
||||
]
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Security policies (pod security standards, image scanning, network policies)",
|
||||
"value": 18
|
||||
},
|
||||
{
|
||||
"label": "Label and annotation standards",
|
||||
"value": 14
|
||||
},
|
||||
{
|
||||
"label": "Network segmentation policies",
|
||||
"value": 6
|
||||
},
|
||||
{
|
||||
"label": "Compliance policies (regulatory requirements, industry standards)",
|
||||
"value": 12
|
||||
},
|
||||
{
|
||||
"label": "Resource governance (limits, requests, quotas)",
|
||||
"value": 9
|
||||
},
|
||||
{
|
||||
"label": "Multi-tenancy policies (namespace isolation, RBAC)",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "Image policies (registry restrictions, vulnerability scanning)",
|
||||
"value": 11
|
||||
},
|
||||
{
|
||||
"label": "Data protection policies (encryption, PVC restrictions)",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "Other custom organizational policies",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"label": "Cost control policies (resource optimization, node selectors)",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"label": "Configuration best practices (probes, anti-affinity)",
|
||||
"value": 7
|
||||
},
|
||||
{
|
||||
"label": "Workload placement policies (node affinity, taints/tolerations)",
|
||||
"value": 6
|
||||
},
|
||||
{
|
||||
"label": "Supply chain security (SBOM, signing verification)",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "0-2 years",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "3-5 years",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"label": "6-10 years",
|
||||
"value": 21
|
||||
},
|
||||
{
|
||||
"label": "11-15 years",
|
||||
"value": 10
|
||||
},
|
||||
{
|
||||
"label": "15+ years",
|
||||
"value": 40
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"label": "Software Developer/Engineer",
|
||||
"value": 26
|
||||
},
|
||||
{
|
||||
"label": "Engineering Manager/Lead",
|
||||
"value": 12
|
||||
},
|
||||
{
|
||||
"label": "Cloud Architect",
|
||||
"value": 11
|
||||
},
|
||||
{
|
||||
"label": "Platform Engineer",
|
||||
"value": 11
|
||||
},
|
||||
{
|
||||
"label": "Site Reliability Engineer (SRE)",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"label": "Security Engineer",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"label": "DevOps Engineer",
|
||||
"value": 3
|
||||
}
|
||||
],
|
||||
"otherResponses": [
|
||||
"IAM Architect",
|
||||
"Software Architect/AI Expert",
|
||||
"Medical information officer",
|
||||
"CTO",
|
||||
"Director of Engineering",
|
||||
"platform/devops/SRE/team lead all in one :/",
|
||||
"Founder",
|
||||
"Security Architect",
|
||||
"Technical lead - A mix of development, architecture and leadership",
|
||||
"Data engineer",
|
||||
"Architect"
|
||||
]
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "any-missing-integrations-or-coverage-for-new-use-c",
|
||||
"title": "Any missing integrations or coverage for new use cases?",
|
||||
"comparisonChartType": null,
|
||||
"chartType": "text-list",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"showCount": true,
|
||||
"maxItems": 100
|
||||
},
|
||||
"tags": [
|
||||
"general"
|
||||
],
|
||||
"rank": 20
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "any-success-and-failures-with-generative-ai-toolin",
|
||||
"title": "Any success and failures with generative AI tooling for Rego and OPA learning?",
|
||||
"comparisonChartType": null,
|
||||
"chartType": "text-list",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"showCount": true,
|
||||
"maxItems": 100
|
||||
},
|
||||
"tags": [
|
||||
"general"
|
||||
],
|
||||
"rank": 19
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"id": "community-project-use",
|
||||
"title": "Community Project Use",
|
||||
"comparisonChartType": "stacked-bar",
|
||||
"chartType": "horizontal-bar",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"xAxisLabel": "Count",
|
||||
"yAxisLabel": "",
|
||||
"showXAxis": true,
|
||||
"showYAxis": true,
|
||||
"showTooltip": true
|
||||
},
|
||||
"tags": [
|
||||
"general"
|
||||
],
|
||||
"rank": 23
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"id": "company-size",
|
||||
"title": "Company Size",
|
||||
"comparisonChartType": "stacked-bar",
|
||||
"chartType": "horizontal-bar",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"xAxisLabel": "Count",
|
||||
"yAxisLabel": "",
|
||||
"showXAxis": true,
|
||||
"showYAxis": true,
|
||||
"showTooltip": true
|
||||
},
|
||||
"tags": [
|
||||
"demographic"
|
||||
],
|
||||
"rank": 73
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "country-of-residence",
|
||||
"title": "Country of Residence",
|
||||
"comparisonChartType": null,
|
||||
"chartType": "horizontal-bar",
|
||||
"featured": false,
|
||||
"chartConfig": {},
|
||||
"tags": [
|
||||
"demographic"
|
||||
],
|
||||
"rank": 72
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "do-you-find-the-documentation-for-opa-envoy-to-be-",
|
||||
"title": "Do you find the documentation for OPA-Envoy to be sufficient?",
|
||||
"comparisonChartType": null,
|
||||
"chartType": "text-list",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"showCount": true,
|
||||
"maxItems": 100
|
||||
},
|
||||
"tags": [
|
||||
"opa-envoy-plugin"
|
||||
],
|
||||
"rank": 57
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "do-you-have-a-need-to-extend-or-replace-kubernetes",
|
||||
"title": "Do you have a need to extend or replace Kubernetes RBAC with more fine-grained authorization?",
|
||||
"comparisonChartType": null,
|
||||
"chartType": "text-list",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"showCount": true,
|
||||
"maxItems": 100
|
||||
},
|
||||
"tags": [
|
||||
"gatekeeper"
|
||||
],
|
||||
"rank": 46
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "do-you-have-any-other-feedback-or-comments-to-shar",
|
||||
"title": "Do you have any other feedback or comments to share about Regal?",
|
||||
"comparisonChartType": null,
|
||||
"chartType": "text-list",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"showCount": true,
|
||||
"maxItems": 100
|
||||
},
|
||||
"tags": [
|
||||
"regal"
|
||||
],
|
||||
"rank": 69
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"id": "does-regal-help-you-find-bugs",
|
||||
"title": "Does Regal help you find bugs?",
|
||||
"comparisonChartType": "stacked-bar",
|
||||
"chartType": "horizontal-bar",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"xAxisLabel": "Count",
|
||||
"yAxisLabel": "",
|
||||
"showXAxis": true,
|
||||
"showYAxis": true,
|
||||
"showTooltip": true
|
||||
},
|
||||
"tags": [
|
||||
"regal"
|
||||
],
|
||||
"rank": 67
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"id": "does-regals-documentation-help-you-fix-the-bugs-yo",
|
||||
"title": "Does Regal's documentation help you fix the bugs you find?",
|
||||
"comparisonChartType": "stacked-bar",
|
||||
"chartType": "horizontal-bar",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"xAxisLabel": "Count",
|
||||
"yAxisLabel": "",
|
||||
"showXAxis": true,
|
||||
"showYAxis": true,
|
||||
"showTooltip": true
|
||||
},
|
||||
"tags": [
|
||||
"regal"
|
||||
],
|
||||
"rank": 68
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"id": "gatekeeper-performance-met-our-needs",
|
||||
"title": "Gatekeeper performance met our needs",
|
||||
"comparisonChartType": "stacked-bar",
|
||||
"chartType": "bar",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"xAxisLabel": "",
|
||||
"yAxisLabel": "Count",
|
||||
"showXAxis": true,
|
||||
"showYAxis": true,
|
||||
"showTooltip": true
|
||||
},
|
||||
"tags": [
|
||||
"gatekeeper"
|
||||
],
|
||||
"rank": 28
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"id": "how-did-you-first-find-out-about-opa",
|
||||
"title": "How did you first find out about OPA?",
|
||||
"comparisonChartType": null,
|
||||
"chartType": "text-list",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"showCount": true,
|
||||
"maxItems": 100
|
||||
},
|
||||
"tags": [
|
||||
"general"
|
||||
],
|
||||
"rank": 18
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"id": "how-do-you-deploy-opa-envoy",
|
||||
"title": "How do you deploy OPA-Envoy?",
|
||||
"comparisonChartType": "stacked-bar",
|
||||
"chartType": "horizontal-bar",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"xAxisLabel": "Count",
|
||||
"yAxisLabel": "",
|
||||
"showXAxis": true,
|
||||
"showYAxis": true,
|
||||
"showTooltip": true
|
||||
},
|
||||
"tags": [
|
||||
"opa-envoy-plugin"
|
||||
],
|
||||
"rank": 52
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"id": "how-do-you-manage-policy-for-opa-envoy",
|
||||
"title": "How do you manage policy for OPA-Envoy?",
|
||||
"comparisonChartType": "stacked-bar",
|
||||
"chartType": "horizontal-bar",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"xAxisLabel": "Count",
|
||||
"yAxisLabel": "",
|
||||
"showXAxis": true,
|
||||
"showYAxis": true,
|
||||
"showTooltip": true
|
||||
},
|
||||
"tags": [
|
||||
"opa-envoy-plugin"
|
||||
],
|
||||
"rank": 54
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"id": "how-do-you-use-opa-for-genai-workloads",
|
||||
"title": "How do you use OPA for GenAI workloads?",
|
||||
"comparisonChartType": "stacked-bar",
|
||||
"chartType": "horizontal-bar",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"xAxisLabel": "Count",
|
||||
"yAxisLabel": "",
|
||||
"showXAxis": true,
|
||||
"showYAxis": true,
|
||||
"showTooltip": true
|
||||
},
|
||||
"tags": [
|
||||
"general"
|
||||
],
|
||||
"rank": 13
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"id": "how-do-you-use-regal",
|
||||
"title": "How do you use Regal?",
|
||||
"comparisonChartType": "stacked-bar",
|
||||
"chartType": "horizontal-bar",
|
||||
"featured": false,
|
||||
"chartConfig": {
|
||||
"xAxisLabel": "Count",
|
||||
"yAxisLabel": "",
|
||||
"showXAxis": true,
|
||||
"showYAxis": true,
|
||||
"showTooltip": true
|
||||
},
|
||||
"tags": [
|
||||
"regal"
|
||||
],
|
||||
"rank": 65
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user