Skip to content

Commit

Permalink
feat: Grammar support and custom theme
Browse files Browse the repository at this point in the history
  • Loading branch information
d-jeffery committed May 6, 2024
1 parent dc71386 commit b0aa9fc
Show file tree
Hide file tree
Showing 22 changed files with 456 additions and 92 deletions.
15 changes: 15 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Dependabot configuration:
# https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuration-options-for-dependency-updates

version: 2
updates:
# Maintain dependencies for Gradle dependencies
- package-ecosystem: "gradle"
directory: "/"
schedule:
interval: "weekly"
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
58 changes: 54 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,63 @@
# openfga4intellij
# OpenFGA plugin for JetBrain IDEs

This is the official IntelliJ plugin for [OpenFGA](https://openfga.dev/) [language for authorization models](https://openfga.dev/docs/configuration-language).

This is an unofficial IntelliJ plugin for [OpenFGA](https://openfga.dev/) support.
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://github.com/openfga/vscode-ext/blob/main/LICENSE)
[![Join our community](https://img.shields.io/badge/slack-cncf_%23openfga-40abb8.svg?logo=slack)](https://openfga.dev/community)
[![Twitter](https://img.shields.io/twitter/follow/openfga?color=%23179CF0&logo=twitter&style=flat-square "@openfga on Twitter")](https://twitter.com/openfga)


## Features
## About

* _Partial_ DSL syntax support (associated with `.fga` and `.openfga` file extensions)
[OpenFGA](https://openfga.dev) is an open source Fine-Grained Authorization solution inspired by [Google's Zanzibar paper](https://research.google/pubs/pub48190/). It was created by the FGA team at [Auth0](https://auth0.com) based on [Auth0 Fine-Grained Authorization (FGA)](https://fga.dev), available under [a permissive license (Apache-2)](https://github.com/openfga/rfcs/blob/main/LICENSE) and welcomes community contributions.

OpenFGA is designed to make it easy for application builders to model their permission layer, and to add and integrate fine-grained authorization into their applications. OpenFGA’s design is optimized for reliability and low latency at a high scale.

## Resources

- [OpenFGA Documentation](https://openfga.dev/docs)
- [OpenFGA API Documentation](https://openfga.dev/api/service)
- [OpenFGA on Twitter](https://twitter.com/openfga)
- [OpenFGA Community](https://openfga.dev/community)
- [Zanzibar Academy](https://zanzibar.academy)
- [Google's Zanzibar Paper (2019)](https://research.google/pubs/pub48190/)


## Installation

### Manual Installation

![manual_install.png](docs/manual_install.png)

## Usage

* DSL syntax support (associated with `.fga` and `.openfga` file extensions)
![syntax.png](docs/syntax.png)
* DSL syntax injection for YAML store files (associated with `.fga.yaml` and `.openfga.yaml` file extensions)
![store_syntax.png](docs/store_syntax.png)
* Authorization model dsl file template
* Authorization model dsl live templates
* Generate json file from DSL (requires [OpenFGA CLI](https://github.com/openfga/cli) to be installed)
![cli_setup.png](docs/cli_setup.png)
* Configure servers in OpenFGA tool window
![server_setup.png](docs/server_setup.png)

## Roadmap

A rough [roadmap](https://github.com/orgs/openfga/projects/1) for development priorities.

## Contributing

See the [DEVELOPMENT](./docs/DEVELOPMENT.md) and [CONTRIBUTING](https://github.com/openfga/.github/blob/main/CONTRIBUTING.md).

## Author

[OpenFGA](https://github.com/openfga)

## Acknowledgments

A special thanks to [Yann D'Isanto](https://github.com/le-yams) for the contribution of [their codebase](https://github.com/le-yams/openfga4intellij), which this project is built upon.

## License

This project is licensed under the Apache-2.0 license. See the [LICENSE](https://github.com/openfga/vscode-ext/blob/main/LICENSE) file for more info.
14 changes: 13 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ plugins {
id("org.jetbrains.kotlin.jvm") version "1.9.21"
id("org.jetbrains.intellij") version "1.16.1"
id("org.jetbrains.grammarkit") version "2022.3.2"

id("jacoco")
}

group = "com.github.le_yams"
Expand All @@ -17,6 +19,8 @@ dependencies {
implementation("dev.openfga:openfga-sdk:0.4.1")
implementation("org.dmfs:oauth2-essentials:0.22.0")
implementation("org.dmfs:httpurlconnection-executor:1.21.3")

testImplementation("junit:junit:4.13.2")
}


Expand All @@ -29,7 +33,7 @@ intellij {
version.set("2023.3")
type.set("IC") // Target IDE Platform

plugins.set(listOf(/* Plugin Dependencies */))
plugins.set(listOf("org.intellij.intelliLang", "org.jetbrains.plugins.yaml"))
}

grammarKit {
Expand Down Expand Up @@ -86,4 +90,12 @@ tasks {
publishPlugin {
token.set(System.getenv("PUBLISH_TOKEN"))
}

test {
finalizedBy(jacocoTestReport)
}

jacocoTestReport {
dependsOn(test)
}
}
17 changes: 17 additions & 0 deletions docs/DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Development and Contributing to the OpenFGA VS Code Extension

Read the [OpenFGA Contribution Process](https://github.com/openfga/.github/blob/main/CONTRIBUTING.md) and the [OpenFGA Code of Conduct](https://github.com/openfga/.github/blob/main/CODE_OF_CONDUCT.md).

## Getting Started

### Run Build & tests

```./gradlew build```

## Distribution (Optional)

To generate an installable build of this plugin, you can do the following:

```./gradlew buildPlugin```

[Instructions for installation from disk](https://www.jetbrains.com/help/idea/managing-plugins.html#install_plugin_from_disk)
Binary file added docs/cli_setup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/manual_install.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/server_setup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/store_syntax.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/syntax.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public class OpenFGAColorSettingsPage implements ColorSettingsPage {
new AttributesDescriptor("Type identifier", OpenFGASyntaxHighlighter.TYPE_IDENTIFIER),
new AttributesDescriptor("Relation name", OpenFGASyntaxHighlighter.RELATION_NAME),
new AttributesDescriptor("Schema version", OpenFGASyntaxHighlighter.SCHEMA_VERSIONS),
new AttributesDescriptor("Bad value", OpenFGASyntaxHighlighter.BAD_CHARACTER)
};

@Nullable
Expand All @@ -37,7 +36,8 @@ public SyntaxHighlighter getHighlighter() {
@NotNull
@Override
public String getDemoText() {
return "model\n" +
return "# Administrator model\n" +
"model\n" +
" schema 1.1\n" +
"\n" +
"type user\n" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,50 @@
import com.github.le_yams.openfga4intellij.psi.OpenFGATypes;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.editor.DefaultLanguageHighlighterColors;
import com.intellij.openapi.editor.HighlighterColors;
import com.intellij.openapi.editor.colors.TextAttributesKey;
import com.intellij.openapi.fileTypes.SyntaxHighlighterBase;
import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;

import static com.intellij.openapi.editor.colors.TextAttributesKey.createTextAttributesKey;

public class OpenFGASyntaxHighlighter extends SyntaxHighlighterBase {
public static final TextAttributesKey KEYWORD =
createTextAttributesKey("KEYWORD", DefaultLanguageHighlighterColors.KEYWORD);
createTextAttributesKey("OPENFGA_KEYWORD", DefaultLanguageHighlighterColors.KEYWORD);
public static final TextAttributesKey SCHEMA_VERSIONS =
createTextAttributesKey("OPENFGA_SCHEMA_VERSIONS", DefaultLanguageHighlighterColors.NUMBER);
public static final TextAttributesKey MODULE_NAME =
createTextAttributesKey("OPENFGA_MODULE_NAME", DefaultLanguageHighlighterColors.CLASS_NAME);
public static final TextAttributesKey RELATION_NAME =
createTextAttributesKey("OPENFGA_RELATION_NAME", DefaultLanguageHighlighterColors.INSTANCE_METHOD);
public static final TextAttributesKey RELATION_REFERENCE =
createTextAttributesKey("OPENFGA_RELATION_REFERENCE", DefaultLanguageHighlighterColors.INSTANCE_METHOD);
public static final TextAttributesKey TYPE_IDENTIFIER =
createTextAttributesKey("OPENFGA_TYPE_IDENTIFIER", DefaultLanguageHighlighterColors.CLASS_NAME);
public static final TextAttributesKey TYPE_REFERENCE =
createTextAttributesKey("OPENFGA_TYPE_REFERENCE", DefaultLanguageHighlighterColors.CLASS_REFERENCE);
public static final TextAttributesKey CONDITION_IDENTIFIER =
createTextAttributesKey("OPENFGA_CONDITION_IDENTIFIER", DefaultLanguageHighlighterColors.CLASS_NAME);
public static final TextAttributesKey CONDITION_REFERENCE =
createTextAttributesKey("OPENFGA_CONDITION_REFERENCE", DefaultLanguageHighlighterColors.CLASS_REFERENCE);
public static final TextAttributesKey CONDITION_PARAM_IDENTIFIER =
createTextAttributesKey("OPENFGA_CONDITION_PARAM_IDENTIFIER", DefaultLanguageHighlighterColors.INSTANCE_METHOD);
public static final TextAttributesKey CONDITION_PARAM_TYPE =
createTextAttributesKey("OPENFGA_CONDITION_PARAM_TYPE", DefaultLanguageHighlighterColors.PARAMETER);
public static final TextAttributesKey COMMENT =
createTextAttributesKey("OPENFGA_COMMENTS", DefaultLanguageHighlighterColors.LINE_COMMENT);
public static final TextAttributesKey BAD_CHARACTER =
createTextAttributesKey("OPENFGA_BAD_CHARACTER", HighlighterColors.BAD_CHARACTER);

private static final TextAttributesKey[] BAD_CHAR_KEYS = new TextAttributesKey[]{BAD_CHARACTER};
private static final TextAttributesKey[] KEYWORD_KEYS = new TextAttributesKey[]{KEYWORD};
private static final TextAttributesKey[] MODULE_NAME_KEY = new TextAttributesKey[]{MODULE_NAME};
private static final TextAttributesKey[] SCHEMA_VERSIONS_KEYS = new TextAttributesKey[]{SCHEMA_VERSIONS};
private static final TextAttributesKey[] RELATION_NAME_KEYS = new TextAttributesKey[]{RELATION_NAME};
private static final TextAttributesKey[] RELATION_REFERENCE_KEYS = new TextAttributesKey[]{RELATION_REFERENCE};
private static final TextAttributesKey[] TYPE_IDENTIFIER_KEYS = new TextAttributesKey[]{TYPE_IDENTIFIER};
private static final TextAttributesKey[] TYPE_REFERENCE_KEYS = new TextAttributesKey[]{TYPE_REFERENCE};
private static final TextAttributesKey[] CONDITION_IDENTIFIER_KEYS = new TextAttributesKey[]{CONDITION_IDENTIFIER};
private static final TextAttributesKey[] CONDITION_REFERENCE_KEYS = new TextAttributesKey[]{CONDITION_REFERENCE};
private static final TextAttributesKey[] CONDITION_PARAM_KEYS = new TextAttributesKey[]{CONDITION_PARAM_IDENTIFIER};
private static final TextAttributesKey[] CONDITION_PARAM_TYPES = new TextAttributesKey[]{CONDITION_PARAM_TYPE};
private static final TextAttributesKey[] COMMENT_KEYS = new TextAttributesKey[]{COMMENT};
private static final TextAttributesKey[] EMPTY_KEYS = new TextAttributesKey[0];

Expand All @@ -50,36 +63,50 @@ public Lexer getHighlightingLexer() {
if (OpenFGATokenSets.SCHEMA_VERSIONS.contains(tokenType)) {
return SCHEMA_VERSIONS_KEYS;
}
if (OpenFGATokenSets.KEYWORDS.contains(tokenType)) {
return KEYWORD_KEYS;

if (tokenType.equals(OpenFGATypes.MODULE_NAME)) {
return MODULE_NAME_KEY;
}

if (tokenType.equals(OpenFGATypes.TYPE_IDENTIFIER)) {
return TYPE_IDENTIFIER_KEYS;
}
if (tokenType.equals(OpenFGATypes.RELATION_DEF_TYPE_RESTRICTION)) {
return TYPE_REFERENCE_KEYS;
}

if (tokenType.equals(OpenFGATypes.RELATION_NAME)) {
return RELATION_NAME_KEYS;
}
if (tokenType.equals(OpenFGATypes.RELATION_DEF_RELATION_ON_SAME_OBJECT)) {
return RELATION_NAME_KEYS;
if (tokenType.equals(OpenFGATypes.REWRITE_TUPLESET_NAME)) {
return RELATION_REFERENCE_KEYS;
}
if (tokenType.equals(OpenFGATypes.REWRITE_COMPUTEDUSERSET_NAME)) {
return RELATION_REFERENCE_KEYS;
}
if (tokenType.equals(OpenFGATypes.REWRITE_TUPLESET_COMPUTEDUSERSET_NAME)) {
return RELATION_NAME_KEYS;
return RELATION_REFERENCE_KEYS;
}
if (tokenType.equals(OpenFGATypes.REWRITE_TUPLESET_NAME)) {
return RELATION_NAME_KEYS;

if (tokenType.equals(OpenFGATypes.CONDITION_NAME_REF)) {
return CONDITION_REFERENCE_KEYS;
}
if (tokenType.equals(OpenFGATypes.RELATION_DEF_TYPE_RESTRICTION_RELATION)) {
return RELATION_NAME_KEYS;
if (tokenType.equals(OpenFGATypes.CONDITION_NAME)) {
return CONDITION_IDENTIFIER_KEYS;
}
if (tokenType.equals(OpenFGATypes.TYPE_IDENTIFIER)) {
return TYPE_IDENTIFIER_KEYS;
if (tokenType.equals(OpenFGATypes.PARAMETER_NAME)) {
return CONDITION_PARAM_KEYS;
}
if (tokenType.equals(OpenFGATypes.RELATION_DEF_TYPE_RESTRICTION_TYPE)) {
return TYPE_REFERENCE_KEYS;
if (tokenType.equals(OpenFGATypes.PARAMETER_TYPE)) {
return CONDITION_PARAM_TYPES;
}

if (OpenFGATokenSets.KEYWORDS.contains(tokenType)) {
return KEYWORD_KEYS;
}
if (OpenFGATokenSets.COMMENTS.contains(tokenType)) {
return COMMENT_KEYS;
}
if (tokenType.equals(TokenType.BAD_CHARACTER)) {
return BAD_CHAR_KEYS;
}

return EMPTY_KEYS;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.github.le_yams.openfga4intellij.inject;

import com.github.le_yams.openfga4intellij.OpenFGALanguage;
import com.intellij.lang.injection.MultiHostInjector;
import com.intellij.lang.injection.MultiHostRegistrar;
import com.intellij.psi.ElementManipulators;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.yaml.psi.YAMLKeyValue;
import org.jetbrains.yaml.psi.YAMLScalarList;

import java.util.List;

public class OpenFGAYamlInjector implements MultiHostInjector {
@Override
public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar,
@NotNull PsiElement context) {

if (!(context instanceof YAMLKeyValue && shouldInject(context))) {
return;
}

PsiLanguageInjectionHost host = (PsiLanguageInjectionHost) ((YAMLKeyValue) context).getValue();
registrar.startInjecting(OpenFGALanguage.INSTANCE);
registrar.addPlace(null, null, host, ElementManipulators.getValueTextRange(host));
registrar.doneInjecting();
}

private boolean shouldInject(PsiElement context) {
return context instanceof YAMLKeyValue &&
(context.getContainingFile().getName().endsWith("fga.yaml") ||
context.getContainingFile().getName().endsWith("openfga.yaml")) &&
((YAMLKeyValue) context).getValue() instanceof YAMLScalarList &&
((YAMLKeyValue) context).getKeyText().equals("model");
}

@Override
public @NotNull List<? extends Class<? extends PsiElement>> elementsToInjectIn() {
return List.of(YAMLKeyValue.class);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.github.le_yams.openfga4intellij.parsing;

import com.intellij.lexer.FlexLexer;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.TokenType;import com.intellij.psi.tree.IElementType;

import static com.intellij.psi.TokenType.BAD_CHARACTER;
import static com.intellij.psi.TokenType.WHITE_SPACE;
Expand All @@ -23,40 +23,49 @@ import static com.github.le_yams.openfga4intellij.psi.OpenFGATypes.*;
%unicode

ALPHA_NUMERIC=[a-zA-Z0-9_-]+
SCHEMA_VERSION=(\d+\.\d+)
END_OF_LINE=(\r\n)|\n
WHITESPACE=[\ \t]
IDENT1=((\ {2})|\t)
IDENT2=((\ {4})|(\t{2}))
SINGLE_LINE_COMMENT=[ \t]*#.*
SINGLE_LINE_COMMENT=[ \t]*#+[^\n]*
// SINGLE_TRAILING_COMMENT=\s+#+[^\n]*
CONDITION_EXPRESSION=(\{[^\}]+\})

%%
<YYINITIAL> {
" " { return WHITE_SPACE; }

"module" { return MODULE; }
"model" { return MODEL; }
"schema" { return SCHEMA; }
"1.1" { return SCHEMA_VERSION_V1_1; }
"type" { return TYPE; }
"extend" { return EXTEND; }
"relations" { return RELATIONS; }
"define" { return DEFINE; }
"#" { return HASH; }
":" { return COLON; }
"*" { return WILDCARD; }
"[" { return L_SQUARE; }
"]" { return R_SQUARE; }
"(" { return L_PAREN; }
")" { return R_PAREN; }
"<" { return LESS; }
">" { return GREATER; }
"," { return COMMA; }
"and" { return AND; }
"or" { return OR; }
"but not" { return BUT_NOT; }
"from" { return FROM; }
"condition" { return CONDITION; }
"with" { return WITH; }

{ALPHA_NUMERIC} { return ALPHA_NUMERIC; }
{SCHEMA_VERSION} { return SCHEMA_VERSION; }
{END_OF_LINE} { return END_OF_LINE; }
{WHITESPACE} { return WHITESPACE; }
{IDENT1} { return IDENT1; }
{IDENT2} { return IDENT2; }
{SINGLE_LINE_COMMENT} { return SINGLE_LINE_COMMENT; }

{WHITESPACE} { return TokenType.WHITE_SPACE; }
^{IDENT1} { return IDENT1; }
^{IDENT2} { return IDENT2; }
^{SINGLE_LINE_COMMENT}$ { return SINGLE_LINE_COMMENT; }
{CONDITION_EXPRESSION} { return CONDITION_EXPRESSION; }
}

[^] { return BAD_CHARACTER; }
[^] { return TokenType.BAD_CHARACTER; }
Loading

0 comments on commit b0aa9fc

Please sign in to comment.